我知道當JS試圖將對象表示爲基元時,它會在對象上調用valueOf
方法。但今天我發現它在相同的情況下也叫toString()
方法:爲什麼JS在對象被添加到數字時調用`toString`方法
var o = {};
o.toString = function() {return 1};
1+ o; // 2
爲什麼?如果我添加valueOf
方法,則不調用toString
。
我知道當JS試圖將對象表示爲基元時,它會在對象上調用valueOf
方法。但今天我發現它在相同的情況下也叫toString()
方法:爲什麼JS在對象被添加到數字時調用`toString`方法
var o = {};
o.toString = function() {return 1};
1+ o; // 2
爲什麼?如果我添加valueOf
方法,則不調用toString
。
這一切都取決於提示。 當你使用1 + o
這是一個數字提示,因爲+
操作數,所以它肯定會在toString
之前使用valueOf
。
如果提示是字符串,則在valueOf
之前使用toString
。例如嘗試["o",o].join("=")
總之是:
var o = {};
o.toString = function() {return 1};
o.valueOf= function(){return 2};
1 + o; // 1+2=3 ==> it takes valueOf value
["o",o].join("") //o1 ==> it takes toString value
我想其原因在於在ECMA-262 specification 8.6.2.6章節:
8.6.2.6 [默認值]
[...]
當[默認值] ]的方法稱爲提示號碼,採取以下步驟:
用參數「valueOf」調用對象O的[[Get]]方法。
如果結果(1)不是一個對象,轉到步驟5
如果Result(3)是原始值,則返回Result(3)。
用參數「toString」調用對象O的[[Get]]方法。
如果結果(5)不是一個對象,轉到步驟9
由於您的對象沒有實現valueOf,因此使用toString。
這是正確的,但我認爲它值得也提及** 11.6.1加法運算符(+)**,即7表示。**如果類型(結果(5) )是字符串或類型(結果(6))是字符串,請轉到步驟12。**,其中Result(5)是** Call ToPrimitive(Result(2))。**。這就是爲什麼總和需要訪問默認值,並且它基於默認值的類型具有不同的行爲。 – rpadovani
TL; DR
當ToPrimitive被稱爲無hint
它充當如果提示是number
。這定義了要調用的方法:首先是valueOf
,然後是toString
。如果你還沒有定義你自己的valueOf
,它會調用Object.prototype.valueOf
返回這個。
BTW在現代瀏覽器,你可以具體談談它
const a = {
[Symbol.toPrimitive]: function(hint) {
console.log(hint);
return {
'default': 1,
'number': 2,
'string': 'three'
}[hint]
}
}
console.log(a + 1); //default, 2
console.log(+a + 1); //number, 3
console.log(`${a} + one`); //string, three + one
朗讀:
感謝您的提示。它絕對暗示爲一個數字。我編輯了我自己的答案感謝你.. –
謝謝,如何確定什麼是提示?存在哪些類型的提示?提示是否連接到'+'運算符? –
@Maximus 提示只是JS執行其操作的一種類型線索。 在我們的上下文中,只會使用兩種類型之一(字符串,數字)。在JS中有6種類型(undefined,null,string,number,object,boolean)。 在我們的例子中是+運算符給JS引擎一個提示,用這個值作爲數字,並且在toString()之前使用方法valueOf() –