Talk about valueOf and toString

Keywords: Javascript

valueOf and toString are methods of Object.prototype. In general, these two methods are rarely called directly, but they will be called when the object is used to participate in the operation. I think most people have the following questions:

  • Which priority is higher, valueOf or toString?
  • Will all scenarios call valueOf and toString?

Conceptual explanation

  • valueOf: returns the original value representation of the object
  • toString: returns the string representation of an object

Before introducing the following content, first understand the conversion rules. The following content explanations are based on this rule table:

valueOf transformation rules

valueOf is the method of Object.prototype. Objects from Object will have this method, but many built-in objects will rewrite this method to suit actual needs.

When it comes to primitive values, we have to talk about primitive types. The primitive types in the JS specification are as follows:

  • Boolean
  • Null
  • Undefined
  • Number
  • String

The rewriting rules for non original values (that is, objects) are as follows:

object valueOf return value
Array Array itself
Boolean Boolean value
Date Returns a timestamp in milliseconds
Function Function itself
Number Numeric value
Object Object itself
String String value

The following rules are validated. If you don't care about the validation process, you can just look at the transformation rules.

It is recommended that you take a look at the validation process so that you can understand it better.

Object Conversion to Boolean Value

  1. Directly convert to true (the same for the wrapper type), do not call valueOf and toString

Object to number

When an object is expected to be used as a number, such as participating in arithmetic operations, the conversion of the object to a number will call the valueOf and toString methods in turn. The specific rules are as follows:

  1. If the object has a valueOf method and returns the original value (string, number, boolean, undefined, null), convert the original value to a number (Nan will be returned if the conversion fails), and return the number
  2. If the object has a toString method and returns the original value (string, number, boolean, undefined, null), convert the original value to a number (Nan will be returned if the conversion fails), and return the number
  3. Conversion failed, throwing TypeError

Object to String

  1. If the object has a toString method and returns the original value (string, number, boolean, undefined, null), the original value is converted to a string and the string is returned
  2. If the object has a valueOf method and returns the original value (string, number, boolean, undefined, null), the original value is converted to a string and the string is returned.
  3. Conversion failed, throwing TypeError

toString transformation rules

object toString return value
Array A comma-separated string, such as [1,2] whose toString return value is "1,2"
Boolean "True"
Date Readable time string, such as "Tue Oct 15 2019 12:20:56 GMT+0800 (China standard time)"
Function JS source code string for declaring functions
Number "Numeric value"
Object "[object Object]"
String String

Verify conversion of objects to original values

valueOf and toString have nothing to say. They are rarely called directly in daily development, but when we use objects as original values, conversion will occur, and the conversion process is a little bit confusing.

Object to Boolean

In order to see the internal transformation process of JS intuitively, I simply rewrite valueOf and toString, and add logs.

// Save the original valueOf
var valueOf = Object.prototype.valueOf;
var toString = Object.prototype.toString;

// Add valueOf logs
Object.prototype.valueOf = function () {
    console.log('valueOf');
    return valueOf.call(this);
};
// Add toString log
Object.prototype.toString = function () {
    console.log('toString');
    return toString.call(this);
};
var a = {};
var b = new Boolean(false);

if (a) {
    console.log(1);
}
if(b) {
    console.log(2);
}

The output of the above example is as follows:

1
2

valueOf and toString are not invoked, which conforms to the transformation rule from object to Boolean value

Object to Number

Example 1

// Save the original valueOf
var valueOf = Object.prototype.valueOf;
var toString = Object.prototype.toString;

// Add valueOf logs
Object.prototype.valueOf = function() {
    console.log('valueOf');
    return valueOf.call(this);
};
// Add toString log
Object.prototype.toString = function() {
    console.log('toString');
    return toString.call(this);
};
var a = {};
console.log(++a);

The output is as follows:

valueOf
toString
NaN

Analysis

  1. valueOf method returns the object itself, not the original value. Continue to execute
  2. toString method returns "[object Object]", which is the original value (string), and converts the string to the number NaN.

Example 2

// Save the original valueOf
var valueOf = Object.prototype.valueOf;
var toString = Object.prototype.toString;

// Add valueOf logs
Object.prototype.valueOf = function () {
    console.log('valueOf');
    return "1"; // Force return to original value
};
// Add toString logs
Object.prototype.toString = function () {
    console.log('toString');
    return toString.call(this);
};
var a = {};
console.log(++a);

The output is as follows:

valueOf
2

Analysis

  1. valueOf returns the original value (string), and directly converts the string to a number to get 1

Object to string

When an object is expected to be used as a string, for example, when a string splices a string and an object is passed in, the conversion occurs.

// Save the original valueOf
var valueOf = Object.prototype.valueOf;
var toString = Object.prototype.toString;

// Add valueOf logs
Object.prototype.valueOf = function () {
    console.log('valueOf');
    return valueOf.call(this);
};
// Add toString log
Object.prototype.toString = function () {
    console.log('toString');
    return toString.call(this);
};
var a = {};
alert(a);

The output is as follows:

toString
// Pop up [object Object object]

Analysis

  1. Calling toString method, the string "[object Object]" is returned, and the object is finally converted to this string

Example 2

// Save the original valueOf
var valueOf = Object.prototype.valueOf;
var toString = Object.prototype.toString;

// Add valueOf logs
Object.prototype.valueOf = function () {
    console.log('valueOf');
    return valueOf.call(this);
};
// Add toString logs
Object.prototype.toString = function () {
    console.log('toString');
    return this;
};
var a = {};
alert(a);

The output is as follows:

toString
valueOf
Uncaught TypeError: Cannot convert object to primitive value
    at 1.js:16

Analysis

  1. Call the toString method, return the original value, continue execution
  2. Call valueOf method, return is not original value, continue to execute
  3. Throw TypeError

Processing of Connecting Strings and Objects with Additional Operators

When testing object-to-string conversion, we found that the following code did not perform as expected:

// Save the original valueOf
var valueOf = Object.prototype.valueOf;
var toString = Object.prototype.toString;

// Add valueOf logs
Object.prototype.valueOf = function () {
    console.log('valueOf');
    return valueOf.call(this);
};
// Add toString logs
Object.prototype.toString = function () {
    console.log('toString');
    return toString.call(this);
};

console.log("a" + {});

The output is as follows:

valueOf
toString
a[object Object]

Doubt

"A"+{} should be expected to use {} as a string, and the toString method should be called first, but this is not the case.

conclusion

The conclusions obtained by searching for information are as follows:

  1. If one object is an object, it follows the object-to-original value conversion process (Date object directly calls toString to complete the conversion, other objects through valueOf conversion, if the conversion is unsuccessful, toString is called)
  2. If both objects are objects, both objects follow Step 1 to convert to strings
  3. Two numbers for arithmetic operation
  4. Two strings, directly concatenated
  5. A string, a number, spliced directly into strings

Interview questions

var a = {};
var b = {};
var c = {};
c[a] = 1;
c[b] = 2;

console.log(c[a]);
console.log(c[b]);

Title Solution

Because the key of an object is a string, A and B in c[a] and c[b] perform the conversion from object to string.

According to the transformation rules, both a and B are converted to [object Object object], so c[a] and c[b] operate on the same key.

The answer is to output two 2, c objects with the final structure as follows:

{
  '[object Object]':2
}

Posted by py343 on Tue, 15 Oct 2019 03:14:47 -0700