我遇到了一个Javascript字符串插值与字符串串联的结果不一样的情况.

下面是代码的简化版本,显示了不同之处:

const mmt = moment();
console.log('concatenated: ' + mmt); // "concatenated: 1651070909974"
console.log(`interpolated: ${mmt}`); // "interpolated: Wed Apr 27 2022 10:48:29 GMT-0400"
console.log('mmt.valueOf(): ' + mmt.valueOf()); // "mmt.valueOf(): 1651070909974"
console.log('mmt.toString(): ' + mmt.toString()); // "mmt.toString(): Wed Apr 27 2022 10:48:29 GMT-0400"

所以我立刻想到这是因为.toString().valueOf()的差异,所以我做了一个小测试对象来验证:

const obj = {
  toString: () => 'toString',
  valueOf: () => 'valueOf',
};

console.log('concatenated: ' + obj); // "concatenated: valueOf"
console.log(`interpolated: ${obj}`); // "interpolated: toString"
console.log('obj.valueOf(): ' + obj.valueOf()); // "obj.valueOf(): valueOf"
console.log('obj.toString(): ' + obj.toString()); // "obj.toString(): toString"

然而,当我try 使用Date对象时(其结果也不同于.toString() vs .valueOf()),我确实得到了相同的行为——这次插值和串联都使用.toString()值:

const dte = new Date();
console.log('concatenated: ' + dte); // "concatenated: Wed Apr 27 2022 10:48:29 GMT-0400 (Eastern Daylight Time)"
console.log(`interpolated: ${dte}`); // "interpolated: Wed Apr 27 2022 10:48:29 GMT-0400 (Eastern Daylight Time)"
console.log('dte.valueOf(): ' + dte.valueOf()); // "dte.valueOf(): 1651070909974"
console.log('dte.toString(): ' + dte.toString()); // "dte.toString(): Wed Apr 27 2022 10:48:29 GMT-0400 (Eastern Daylight Time)"

So my questions is:连接与插值时,插值如何转换为字符串的实际规则是什么?为什么日期似乎与其他对象不同?(我试着go 查这个,但到目前为止我的谷歌搜索没有成功…)

JSFiddle Example

推荐答案

行为上的差异实际上与+操作员有关,其背后有一个特定的程序:

抽象操作ToPrimitive上的ECMAScript规范规定,如果没有提供类型提示(如the + operator中的情况),则会发生以下情况:

  • 如果对象有一个Symbol.toPrimitive方法,那么将调用它(提示"default").此方法可以将调用转发到toString.Date个对象就是这种情况.
  • 如果对象没有这样的方法,"number"是默认值,将调用valueOf.moment对象就是这样.

在处理+运算符时,这个复杂过程的原因是它还用于算术加法.

这种复杂性在判断模板文本时并不存在,因为总是string concatenation,因此将使用"string"提示(而不是"default")调用Symbol.toPrimitive方法,或者如果该方法不存在,将调用toString.

所以你假设+是一个纯字符串连接,并不是那么准确.看看当你使用.concat方法时它是如何不同的:

const mmt = moment();
console.log('concatenated: '.concat(mmt));
// Not same result as with +
console.log('plus operator: ' + mmt);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.3/moment.min.js"></script>

Javascript相关问答推荐

不渲染具有HTML参数的React元素

为什么我达到了时间限制!?LeetCode链接列表循环(已解决,但需要解释!)

如何通过onClick为一组按钮分配功能;

React Native平面列表自动滚动

使用JavaScript在ionic Web应用程序中更新.pane和.view的背景 colored颜色

我试图实现用户验证的reduxstore 和操作中出了什么问题?

Plotly热图:在矩形上zoom 后将zoom 区域居中

类型自定义lazy Promise. all

. NET中Unix时间转换为日期时间的奇怪行为

Prisma具有至少一个值的多对多关系

单个HTML中的多个HTML文件

在forEach循环中获取目标而不是父对象的属性

当我在Reaction中创建一个输入列表时,我的输入行为异常

使用插件构建包含chart.js提供程序的Angular 库?

当从其他文件创建类实例时,为什么工作线程不工作?

未找到用于 Select 器的元素:in( puppeteer 师错误)

从异步操作返回对象

JQuery使用选项填充HTMLSELECT并设置默认结果,默认结果显示为空

当S点击按钮时,我如何才能改变它的样式?

如何使用fltter_js将对象作为参数传递给javascrip?