valueOf和toString是Object.prototype的方法。通常不多直接調用,可是在使用對象參與運算的時候就會調用這兩個方法了。我想大部分人都存在如下疑問:javascript
在介紹下面的內容以前先了解一下轉換規則,下面的內容解釋都是基於這個規則表來的:java
valueOf是Object.prototype的方法,由Object來的對象都會有該方法,可是不少內置對象會重寫這個方法,以適合實際須要。面試
說到原始值就必須說到原始類型,JS規範中 原始類型 以下:數組
非原始值(也就是對象)重寫規則以下:函數
對象 | valueOf返回值 |
---|---|
Array | 數組自己 |
Boolean | 布爾值 |
Date | 返回毫秒形式的時間戳 |
Function | 函數自己 |
Number | 數字值 |
Object | 對象自己 |
String | 字符串值 |
如下規則是通過驗證的,若是對驗證過程不關心,能夠只看轉換規則。建議看一下驗證過程,這樣能夠加深理解測試
在預期會將對象用做數字使用時,好比參與算術運算等等操做,對象轉換爲數字會依次調用valueOf和toString方法,具體規則以下:this
valueOf
方法且返回原始值(string、number、boolean、undefined、null),則將該原始值轉換爲數字(轉換失敗會返回NaN),並返回這個數字toString
方法且返回原始值(string、number、boolean、undefined、null),則將該原始值轉換爲數字(轉換失敗會返回NaN),並返回這個數字toString
方法且返回原始值(string、number、boolean、undefined、null),則將該原始值轉換爲字符串,並返回該字符串valueOf
方法且返回原始值(string、number、boolean、undefined、null),則將該原始值轉換爲字符串,並返回該字符串對象 | toString返回值 |
---|---|
Array | 以逗號分割的字符串,如[1,2]的toString返回值爲"1,2" |
Boolean | "True" |
Date | 可讀的時間字符串,如"Tue Oct 15 2019 12:20:56 GMT+0800 (中國標準時間)" |
Function | 聲明函數的JS源代碼字符串 |
Number | "數字值" |
Object | "[object Object]" |
String | "字符串" |
光看valueOf和toString沒啥東西可說,平常開發中也不多直接調用,可是當咱們將對象當作原始值來使用時會發生轉換,並且轉換過程還略微有點迷糊。spa
爲了可以直觀的看到JS內部的轉換過程,我把valueOf和toString都簡單重寫了,加了日誌。prototype
// 保存原始的valueOf var valueOf = Object.prototype.valueOf; var toString = Object.prototype.toString; // 添加valueOf日誌 Object.prototype.valueOf = function () { console.log('valueOf'); return valueOf.call(this); }; // 添加toString日誌 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); }
以上例子的輸出以下:日誌
1 2
未調用valueOf和toString,符合[對象到布爾值]的轉換規則
// 保存原始的valueOf var valueOf = Object.prototype.valueOf; var toString = Object.prototype.toString; // 添加valueOf日誌 Object.prototype.valueOf = function() { console.log('valueOf'); return valueOf.call(this); }; // 添加toString日誌 Object.prototype.toString = function() { console.log('toString'); return toString.call(this); }; var a = {}; console.log(++a);
輸出以下:
valueOf toString NaN
// 保存原始的valueOf var valueOf = Object.prototype.valueOf; var toString = Object.prototype.toString; // 添加valueOf日誌 Object.prototype.valueOf = function () { console.log('valueOf'); return "1"; // 強制返回原始值 }; // 添加toString日誌 Object.prototype.toString = function () { console.log('toString'); return toString.call(this); }; var a = {}; console.log(++a);
輸出以下:
valueOf 2
在預期會將對象用做字符串時,好比一個字符串拼接了字符串,傳入了一個對象,此時會發生轉換。
// 保存原始的valueOf var valueOf = Object.prototype.valueOf; var toString = Object.prototype.toString; // 添加valueOf日誌 Object.prototype.valueOf = function () { console.log('valueOf'); return valueOf.call(this); }; // 添加toString日誌 Object.prototype.toString = function () { console.log('toString'); return toString.call(this); }; var a = {}; alert(a);
輸出以下:
toString // 彈出[object Object]
// 保存原始的valueOf var valueOf = Object.prototype.valueOf; var toString = Object.prototype.toString; // 添加valueOf日誌 Object.prototype.valueOf = function () { console.log('valueOf'); return valueOf.call(this); }; // 添加toString日誌 Object.prototype.toString = function () { console.log('toString'); return this; }; var a = {}; alert(a);
輸出以下:
toString valueOf Uncaught TypeError: Cannot convert object to primitive value at 1.js:16
在測試對象到字符串轉換時發現以下代碼的表現和預期並不一致:
// 保存原始的valueOf var valueOf = Object.prototype.valueOf; var toString = Object.prototype.toString; // 添加valueOf日誌 Object.prototype.valueOf = function () { console.log('valueOf'); return valueOf.call(this); }; // 添加toString日誌 Object.prototype.toString = function () { console.log('toString'); return toString.call(this); }; console.log("a" + {});
輸出以下:
valueOf toString a[object Object]
"a"+ {}
應該是預期把{}
當作字符串使用,應該先調用toString方法的,實際狀況卻不是這樣。
經過查找資料獲得的結論以下:
var a = {}; var b = {}; var c = {}; c[a] = 1; c[b] = 2; console.log(c[a]); console.log(c[b]);
因爲對象的key是字符串,因此c[a]
和c[b]
中的a
和b
會執行[對象到字符串]的轉換。
根據轉換規則, a
和b
都轉換爲了[object Object]
,因此c[a]
和c[b]
操做的是同一個鍵。
答案是輸出兩個2
,c對象的最終結構以下:
{ '[object Object]':2 }