nonopolarity
nonopolarity

Reputation: 151036

Within the standard JavaScript ES6 environment, when is .toString() ever called?

I only found that the time .toString() is called is with string concatenation and string interpolation:

// Inside of Node:

> let arr = [1,3,5];

> arr.toString()
'1,3,5'

> "" + arr
'1,3,5'

> arr + ""
'1,3,5'

> `${arr}`
'1,3,5'

Supposedly, console.log prints out the string representation of the object and is supposed to use toString(), but I am not sure whether it is toString() not properly implemented usually, so console.log does something else:

> console.log(arr);
[ 1, 3, 5 ]

> console.log("arr is %s", arr);
arr is [ 1, 3, 5 ]

So inside the JavaScript itself, when is toString() ever called?

I think by polymorphism, anything we write ourselves, we can use ourObj.toString() to get the string representation of our object as string. But I wonder within JavaScript itself (all its function, libraries, classes), when is toString() actually invoked?

Upvotes: 1

Views: 158

Answers (2)

nonopolarity
nonopolarity

Reputation: 151036

To illustrate some perhaps more common cases:

  1. String interpolation (probably most useful)
  2. String addition or concatenation
  3. Creation of a symbol or string
  4. As a property key
  5. Used by Array's join()

Inside of Node console:

> let foo = { a: 123, toString: function() { return `an object with value ${this.a}`; } };

> foo
{ a: 123, toString: [Function: toString] }

> foo.toString()
'an object with value 123'

> foo.a = 456;
456

> foo.toString()
'an object with value 456'

> `${foo}`
'an object with value 456'

> "foo: " + foo
'foo: an object with value 456'

> "foo: ".concat(foo)
'foo: an object with value 456'

> let d = {};

> d[foo] = "hello";
'hello'

> d
{ 'an object with value 456': 'hello' }

> Symbol(foo)
Symbol(an object with value 456)

> String(foo)
'an object with value 456'

> let bar = Object.assign({}, foo);   // clone

> bar.a = 789;
789

> [foo, bar].join(" - ")
'an object with value 456 - an object with value 789'

Upvotes: 0

trincot
trincot

Reputation: 350310

In several sections of the EcmaScript language specification, there is mention of toString. One important use occurs in the abstract operation OrdinaryToPrimitive: this function will look for the object's toString or valueOf method, and execute it. The precedence can be influenced by a hint argument.

In turn, OrdinaryToPrimitive is called by the abstract operation ToPrimitive

ToPrimitive is called by ToNumber, ToString, ToPropertyKey, relational comparison, equality comparison, evaluation of expressions, the Date constructor, several stringification methods, like toJSON, ...etc.

In fact, the language is soaked with internal operations that will get to executing ToPrimitive. The specification has 200+ references to ToString.

Examples

Here is a object with a toString method implementation in order to prove that toString is called internally.

Then follow a few expressions that each trigger toString.

// Preparation
let obj = {
    toString() {
        this.i = (this.i||0) + 1; // counter
        console.log("call #" + this.i);
        return "0";
    }
};

// Trigger toString via several constructs
({})[obj];
1 < obj; 
1 == obj;
1 + obj;
1 - obj;
+obj;
Math.abs(obj);
parseInt(obj);
new Date(obj);
new RegExp(obj);
new Number(obj);
Symbol(obj); 
"".localeCompare(obj);
[obj, null].sort();
[obj].join();
`${obj}`;
setTimeout(obj); // Not standard EcmaScript environment, but defined in the agent.

Some of these would not trigger toString() if there were a valueOf method defined on obj which would return a primitive value.

Upvotes: 3

Related Questions