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
- 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:
- 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
- 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
- Conversion failed, throwing TypeError
Object to String
- 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
- 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.
- 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
- valueOf method returns the object itself, not the original value. Continue to execute
- 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
- 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
- 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
- Call the toString method, return the original value, continue execution
- Call valueOf method, return is not original value, continue to execute
- 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:
- 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)
- If both objects are objects, both objects follow Step 1 to convert to strings
- Two numbers for arithmetic operation
- Two strings, directly concatenated
- 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 }