JavaScript字符串插值与字符串串联给出了不同的结果

发布于 2025-01-24 11:44:44 字数 1790 浏览 0 评论 0原文

我遇到了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() and 和.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"

但是,当我尝试使用一个日期对象尝试此对象时(与.toString() vs .valueof()有不同的结果。 ),我做不是获得相同的行为 - 这段时间的插值和串联都使用.toString() value:

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)"

,所以我的问题是:在串联与插值时,插值值如何转换为字符串的实际规则是什么?为什么日期似乎与其他对象有所不同? (我已经尝试查找此问题,但是到目前为止,我的谷歌搜索没有成功...)

I ran across a case where Javascript string interpolation is not giving the same result as string concatenation.

Here is a simplified version of the code showing the difference:

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"

So my immediate thought was that it was due to a difference in .toString() and .valueOf(), so I made a small test object to verify:

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"

However, when I tried this with a Date object (which also has a different result from .toString() vs .valueOf()), I do not get the same behavior--this time interpolation and concatenation both use the .toString() value:

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: What are the actual rules for how an interpolated value is converted to a string when concatenated vs interpolated, and why does Date seem to be different from other objects? (I have tried to look this up, but thus far my googling has been unsuccessful...)

JSFiddle Example

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

雪落纷纷 2025-01-31 11:44:44

行为的差异确实与+运算符有关,该操作员背后有一个特定的过程:

摘要操作上的ecmascript规范 toprivitive 指定如果没有提供类型提示(如 +操作员)发生以下情况:

  • 如果对象具有symbor.tprimitive方法,那么它将称为(带有提示“默认”)。此方法可以将调用转发到toStringdate对象就是这种情况。
  • 如果对象没有这样的方法,则“ number”为默认值, valueof 将被调用。 MONM对象就是这种情况。

处理+运算符时,此复杂过程的原因是,它也用于算术添加。

在评估模板文字中不存在这种复杂性,其中始终是字符串串联的意图,因此符号。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>

The difference in behaviour is really related to the + operator, which has a specific procedure behind it:

The ECMAScript specification on the abstract operation ToPrimitive specifies that if no type hint is provided (as is the case with the + operator) the following happens:

  • If the object has a Symbol.toPrimitive method, then it will be called (with hint "default"). This method may forward the call to toString. This is the case with Date objects.
  • If the object has no such method, "number" is the default and valueOf will be called. This is the case with the moment object.

The reason for this complex procedure in handling the + operator, is that it also serves for the arithmetic addition.

This complexity is not present in evaluating template literals, where always string concatenation is intended, and so the Symbol.toPrimitive method will be called with the "string" hint (instead of "default"), or if that method does not exist, toString will be called.

So your assumption that + is a pure string concatenation, is not that accurate. See how it is also different when you use the .concat method:

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>

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文