Me encontré con un caso en el que la interpolación de cadenas de Javascript no da el mismo resultado que la concatenación de cadenas.
Aquí hay una versión simplificada del código que muestra la diferencia:
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" Así que mi pensamiento inmediato fue que se debía a una diferencia en .toString() y .valueOf() , así que hice un pequeño objeto de prueba para verificar:
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" Sin embargo, cuando probé esto con un objeto Date (que también tiene un resultado diferente de .toString() frente .valueOf() ), no obtuve el mismo comportamiento; esta vez, la interpolación y la concatenación usan .toString() valor:
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)"Entonces, mi pregunta es: ¿Cuáles son las reglas reales sobre cómo un valor interpolado se convierte en una cadena cuando se concatena frente a interpolado, y por qué la Fecha parece ser diferente de otros objetos? (He intentado buscar esto, pero hasta ahora mi búsqueda en Google no ha tenido éxito...)
La diferencia de comportamiento está realmente relacionada con el operador + , que tiene un procedimiento específico detrás:
La especificación de ECMAScript sobre la operación abstracta ToPrimitive especifica que si no se proporciona ninguna sugerencia de tipo (como es el caso con el operador + ), ocurre lo siguiente:
Symbol.toPrimitive , entonces se llamará (con la sugerencia "predeterminado"). Este método puede reenviar la llamada a toString . Este es el caso de los objetos Date .valueOf . Este es el caso del objeto de moment . La razón de este complejo procedimiento en el manejo del operador + , es que también sirve para la suma aritmética.
Esta complejidad no está presente en la evaluación de literales de plantilla, donde siempre se pretende la concatenación de cadenas , por lo que se llamará al método Symbol.toPrimitive con la sugerencia de "cadena" (en lugar de "predeterminado"), o si ese método no existe, toString sera llamado.
Entonces, su suposición de que + es una concatenación de cadenas pura, no es tan precisa. Vea cómo también es diferente cuando usa el método .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>