Home > Software engineering >  Javascript string interpolation gives different result than string concatenation
Javascript string interpolation gives different result than string concatenation

Time:04-28

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

CodePudding user response:

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

The ECMAScript specification on 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 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>

  • Related