前言
- 最近在網(wǎng)上看到一個(gè)面試題:(a== 1 && a ==2 && a==3)有可能返回true嗎?答案是可以的,下面來具體講解一下。
valueOf和toString
這個(gè)問題的一個(gè)關(guān)鍵點(diǎn)就是在于利用
==雙等號工作原理,==和===有什么區(qū)別呢?最主要的就是用==的時(shí)候會涉及到類型轉(zhuǎn)換,如果雙等號兩邊數(shù)據(jù)類型不同會嘗試將他們轉(zhuǎn)化為同一類型?;A(chǔ)數(shù)據(jù)類型之間的轉(zhuǎn)換是比較簡單的,這里來說一下對象類型在使用==時(shí)產(chǎn)生的隱形轉(zhuǎn)換。-
valueOf和toString這兩個(gè)方法是每個(gè)對象都自帶的(繼承自O(shè)bject原型),我們先定義一個(gè)簡單的對象然后調(diào)用他的這兩個(gè)方法來看下結(jié)果:
image 可以看到toString返回一個(gè)字符串
"[object Object]",valueOf則是直接返回對象本身,而c=="[object Object]"也為true則說明了在隱式轉(zhuǎn)換的過程中,調(diào)用了c的toString方法。
實(shí)現(xiàn)
- 到這里我們只要重新定義一下變量a,重寫它的toString方法就可以實(shí)現(xiàn)我們要達(dá)到的目的了:
let a = {
i: 1,
toString () {
return a.i++
}
}
if(a == 1 && a == 2 && a == 3) {
console.log('Hello World!');
}
// 輸出Hello World!
- 這里說下具體的過程:執(zhí)行
a==1時(shí),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了。 - 其實(shí)重寫valueOf方法也可以實(shí)現(xiàn),而且轉(zhuǎn)化時(shí)會優(yōu)先調(diào)用valueOf方法:
var c = {
toString () {
console.log('toString')
},
valueOf () {
console.log('valueOf')
}
}
c == 1
// console輸出'valueOf'
結(jié)語
- 這個(gè)問題看起來是解決了,但其實(shí)在實(shí)際項(xiàng)目中去重寫原生對象的
toString或valueOf方法是很不應(yīng)該的,比如toString本來是一定會返回一個(gè)字符串結(jié)果的,重寫后返回其他類型反而容易出問題。
