這里考核的其實(shí)是非嚴(yán)格相等運(yùn)算符==
的原理田轧,下面是摘自MDN的解釋推沸。
相等操作符比較兩個(gè)值是否相等涩蜘,在比較前將兩個(gè)被比較的值轉(zhuǎn)換為相同類型。在轉(zhuǎn)換后(等式的一邊或兩邊都可能被轉(zhuǎn)換)驮配,最終的比較方式等同于全等操作符 === 的比較方式娘扩。
相等操作符對(duì)于不同類型的值,進(jìn)行的比較如下圖所示:
在上面的表格中壮锻,ToNumber(A) 嘗試在比較前將參數(shù) A 轉(zhuǎn)換為數(shù)字琐旁,這與 +A(單目運(yùn)算符+)的效果相同。ToPrimitive(A)通過(guò)嘗試調(diào)用 A 的A.toString() 和 A.valueOf() 方法躯保,將參數(shù) A 轉(zhuǎn)換為原始值(Primitive)旋膳。
結(jié)合這道題,B的類型是Number途事,那么在A==B
的比較中验懊,可能存在兩種情況的轉(zhuǎn)換:
- 如果A類型是
String
和Boolean
,則通過(guò)ToNumber()
轉(zhuǎn)換尸变,它通過(guò)一元正號(hào)+
(也等同于Number()
函數(shù))實(shí)現(xiàn)义图。這種實(shí)現(xiàn)是js語(yǔ)言內(nèi)置的,無(wú)法重寫召烂。 - 如果A類型是
Object
碱工,則通過(guò)toString()
和valueOf()
方法實(shí)現(xiàn)。這兩個(gè)方法是A的方法奏夫,是可以重寫的怕篷。
所以思路就有了,首先確定A是一個(gè)對(duì)象酗昼,然后通過(guò)重寫A的toString()
和valueOf()
方法來(lái)達(dá)到目的廊谓。
所以代碼是:
let a={
num:1,
toString(){
return a.num++
}
}
a==1&&a==2&&a==3 // true
或者:
let a={
num:1,
valueOf(){
return a.num++
}
}
a==1&&a==2&&a==3 // true
延伸
稍微修改上面的代碼再來(lái)兩個(gè)小測(cè)試,就能發(fā)現(xiàn)更多有意思的細(xì)節(jié):
- 在轉(zhuǎn)換的時(shí)候麻削,會(huì)先調(diào)用
a.valueOf()
方法蒸痹,然后依照返回的值(假定叫res
)做下一步的轉(zhuǎn)換。 - 如果
res
是Object的類型呛哟,則接下來(lái)調(diào)用a.toString()
方法叠荠。 - 否則,不再繼續(xù)調(diào)用
a.toString()
方法扫责,而是依據(jù)上表榛鼎,對(duì)res
做相應(yīng)的轉(zhuǎn)換,比如返回的是String
或者Boolean
,則進(jìn)行ToNumber(res)
轉(zhuǎn)換者娱。
下面是測(cè)試代碼:
// valueOf返回Object的情況
let a={
num:1,
toString(){
console.log('toString')
return a.num++
},
valueOf(){
console.log('valueOf')
return {num:2}
}
}
a==1
// valueOf
// toString
// true
// valueOf返回Boolean的情況
let a={
num:1,
toString(){
console.log('toString')
return a.num++
},
valueOf(){
console.log('valueOf')
return true
}
}
a==1
// valueOf
// true
// valueOf返回String的情況
let a={
num:1,
toString(){
console.log('toString')
return a.num++
},
valueOf(){
console.log('valueOf')
return '1'
}
}
a==1
// valueOf
// true
參考鏈接:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Equality_comparisons_and_sameness
https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/57