前言
- 最近在網(wǎng)上看到一個面試題:(a== 1 && a ==2 && a==3)有可能返回true嗎?答案是可以的,下面來具體講解一下科盛。
valueOf和toString
這個問題的一個關(guān)鍵點就是在于利用
==
雙等號工作原理,==
和===
有什么區(qū)別呢?最主要的就是用==
的時候會涉及到類型轉(zhuǎn)換老速,如果雙等號兩邊數(shù)據(jù)類型不同會嘗試將他們轉(zhuǎn)化為同一類型⊥怪鳎基礎(chǔ)數(shù)據(jù)類型之間的轉(zhuǎn)換是比較簡單的橘券,這里來說一下對象類型在使用==
時產(chǎn)生的隱形轉(zhuǎn)換。-
valueOf和toString這兩個方法是每個對象都自帶的(繼承自O(shè)bject原型)卿吐,我們先定義一個簡單的對象然后調(diào)用他的這兩個方法來看下結(jié)果:
可以看到toString返回一個字符串
"[object Object]"
旁舰,valueOf則是直接返回對象本身,而c=="[object Object]"
也為true則說明了在隱式轉(zhuǎn)換的過程中嗡官,調(diào)用了c的toString方法箭窜。
實現(xiàn)
- 到這里我們只要重新定義一下變量a,重寫它的toString方法就可以實現(xiàn)我們要達到的目的了:
let a = {
i: 1,
toString () {
return a.i++
}
}
if(a == 1 && a == 2 && a == 3) {
console.log('Hello World!');
}
// 輸出Hello World!
- 這里說下具體的過程:執(zhí)行
a==1
時谨湘,js引擎會嘗試把對象類型a轉(zhuǎn)化為數(shù)字類型绽快,首先調(diào)用a的valueOf方法來判斷,不行則繼續(xù)調(diào)用toString方法紧阔,然后再把toString返回的字符串轉(zhuǎn)化為數(shù)字類型再去和a作比較(這里我重寫了toString就直接返回的數(shù)字類型的結(jié)果坊罢,正常情況toString返回的字符串)。 - 所以每一次使用
==
判斷都會調(diào)用一次a的toString方法擅耽,返回i屬性的值活孩,然后使a的i屬性加1,這樣最后的判斷結(jié)果自然就為true了乖仇。 - 其實重寫valueOf方法也可以實現(xiàn)憾儒,而且轉(zhuǎn)化時會優(yōu)先調(diào)用valueOf方法:
var c = {
toString () {
console.log('toString')
},
valueOf () {
console.log('valueOf')
}
}
c == 1
// console輸出'valueOf'
結(jié)語
- 這個問題看起來是解決了询兴,但其實在實際項目中去重寫原生對象的
toString
或valueOf
方法是很不應(yīng)該的,比如toString
本來是一定會返回一個字符串結(jié)果的起趾,重寫后返回其他類型反而容易出問題诗舰。