This tutorial says that when Object.prototype.toString() gets overriden, it should only return a primitive value:
The
toString()
function you create must return a primitive, otherwise it will be ignored.
However, in the following example we return a object inside of toString() and it returns the object normally:
var ob2 = {
val1: 100,
val2: 200,
toString: function() {
return {
veh: "meh"
}; //object
}
};
console.log(ob2.toString())
Output:
{veh: 'meh'}
So the toString()
returns the object normally. What is up with the misinformation?
CodePudding user response:
You’re right, the documentation was misleading and incomplete.
I’ll submit a PR when I have time.
I think what the author was referring to was the consequence of the OrdinaryToPrimitive abstract operation in the specification: when a value is coerced to a primitive, the two methods toString
and valueOf
(the methodNames) will be called in a specific order based on a type hint.
And then:
- For each element name of methodNames, do
- Let method be ? Get(O, name).
- If IsCallable(method) is true, then
This step is a loop, iterating over the list of method names. It takes the next method from the list of methodNames, checks if it is a function, calls it, and stores its result in result. Then it performs the type check. If it’s a primitive, i.e. not an object, this result is returned. Otherwise, the loop continues, effectively ignoring the result.
If the loop reaches the end without returning a value, a TypeError will be thrown.
In order to demonstrate this behavior, you have to have both methods:
class Test1 {
toString() {
return "1";
}
valueOf() {
return "2";
}
}
class Test2 {
toString() {
return {};
}
valueOf() {
return "2";
}
}
class Test3 {
toString() {
return "1";
}
valueOf() {
return {};
}
}
class Test4 {
toString() {
return {};
}
valueOf() {
return {};
}
}
const test1 = new Test1,
test2 = new Test2,
test3 = new Test3,
test4 = new Test4;
console.log(String(test1)); // "1"; toString is preferred.
// `"" test1` and ` test1` also demonstrate this.
console.log(Number(test1)); // 2; valueOf is preferred.
console.log(String(test2)); // "2"; toString is ignored; valueOf is chosen instead.
console.log(Number(test2)); // 2; valueOf is preferred.
console.log(String(test3)); // "1"; toString is preferred.
console.log(Number(test3)); // 1; valueOf is ignored; toString is chosen instead.
console.log(String(test4)); // TypeError; none of the methods returns a primitive.
console.log(Number(test4)); // TypeError; none of the methods returns a primitive.
What the documentation didn’t refer to was explicitly calling the toString
method, because that works just fine:
class Test {
toString() {
return {
hello: "world"
};
}
}
const test = new Test;
console.log(test.toString()); // Logs { hello: "world" }.