前言
- 最近在網(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é)果的开瞭,重寫后返回其他類型反而容易出問題。