I'm refactoring some code and I want to make sure I'm not missing any edge cases. I don't know if I understand all the details of template literals.
Are there any reasonable cases where these three log messages will be different?
try {
throw new Error('test error');
} catch (error) {
console.log(`sample error message: ${error.toString()}`)
console.log(`sample error message: ${String(error)}`)
console.log(`sample error message: ${error}`);
}
CodePudding user response:
If you follow the good practice of always throwing an instance of Error
, then you can reasonably assume they'll always be the same. Even if you don't follow this good practice, these will probably behave the same. It takes some odd tricks to make them behave differently.
Here's one example, where I've created a null-prototype object (so it doesn't have a default toString() method), then I provided a valueOf() definition to this object and threw it. String coercion will fall back to using valueOf()
if toString()
is not present, so the first two logs work. The last one will not, because it's explicitly trying to use the toString()
function that does not exist.
try {
const err = Object.create(null);
err.valueOf = () => 42;
throw err;
} catch (error) {
console.log(`sample error message: ${String(error)}`);
console.log(`sample error message: ${error}`);
console.log(`sample error message: ${error.toString()}`);
}
For further reading, I would look at this section of MDN's toString page. It seems to allude that using String(value)
and '' value
act the same (coercion from using template string would also act the same as string concatenation), though I would need to check the JavaScript spec to be 100% sure on this. In particular, it sounds like both of these will call toString()
, unless this Symbol.toPrimitive function is defined on the object, in which case that would take higher precedence.
In general, it seems you're safest if you swap between String(error)
and concatenating a string with your value. Using .toString()
has the most differences, as that won't take into account the potential presence of Symbol.toPrimitive
or valueOf()
when converting.