面試官: (a==1 && a==2 && a==3) 能否在 JavaScript 中為“真”?
最近,我被問到一個(gè)非常有趣的面試問題:Can (a== 1 && a==2 && a==3) ever evaluate to true in JavaScript?。 我?guī)缀跏チ斯ぷ鳈C(jī)會(huì),因?yàn)槲覠o法回答。
那一刻,我被這個(gè)問題嚇了一跳,以為面試官在開玩笑。
但當(dāng)我看到他的“微笑”時(shí),一種“你一定不知道答案”的感覺掠過我的腦海,這絕對不是一個(gè)容易解決的問題。
文章將給出6個(gè)專業(yè)答案,讓我們馬上開始吧。
解決方案一:valueOf && toString
第一個(gè)解決方案非常簡單,相信你在閱讀此代碼后會(huì)有一個(gè)想法。
let a = {
name: 'fatfish',
toString () {
return 'medium'
}
}
if (a == 'medium') {
console.log('hello medium')
}
太神奇了,這是怎么回事? 別擔(dān)心,我的朋友,我會(huì)盡力解釋原因。
解釋部分隱式轉(zhuǎn)換規(guī)則
在 JavaScript 中使用 == 比較兩個(gè)值時(shí),會(huì)執(zhí)行以下操作:
- 將兩個(gè)比較的值轉(zhuǎn)換為相同的類型。
- 轉(zhuǎn)換后(等式的一側(cè)或兩側(cè)可以轉(zhuǎn)換),比較值。
比較規(guī)則如下表所示:
從表中可以得到一些信息。 為了使 (a == 1),a 只能是以下幾種情況:
- a 的類型是 String,可以轉(zhuǎn)換為數(shù)字 1('1' == 1 => true)。
- a 的類型是布爾值,可以轉(zhuǎn)換為數(shù)字 1 (true == 1 => true)。
- a的類型是Object,可以通過“轉(zhuǎn)換機(jī)制”轉(zhuǎn)換為數(shù)字1。
對象到原始類型的“轉(zhuǎn)換機(jī)制”
規(guī)則 1 和規(guī)則 2 沒有什么特別之處,我們來看看規(guī)則 3:
當(dāng)對象轉(zhuǎn)換為原始類型時(shí),會(huì)調(diào)用內(nèi)置的 [ToPrimitive] 函數(shù)。
邏輯大致如下:
- 如果有 Symbol.toPrimitive 方法,則先調(diào)用。
- 調(diào)用valueOf,如果可以轉(zhuǎn)成原來的類型,則返回。
- 調(diào)用toString,如果能轉(zhuǎn)換成原來的類型,則返回。
- 如果沒有返回原始類型,則會(huì)報(bào)錯(cuò)。
const obj = {
value: 1,
valueOf() {
return 2
},
toString() {
return '3'
},
[Symbol.toPrimitive]() {
return 4
}
}
obj == 4
我的朋友,感謝你非常耐心地閱讀了這么長時(shí)間,我相信你心中已經(jīng)有了答案。
let a = {
i: 1,
valueOf() {
return this.i++
}
}
if (a == 1 && a == 2 && a == 3) {
console.log('hello medium')
}
解決方案 2:數(shù)組 && 連接
數(shù)組對象的隱式轉(zhuǎn)換也符合規(guī)則 3,但會(huì)在“toString”之前調(diào)用“join”方法。 所以你可以從這里開始。
let a = [1, 2, 3]
a.join = a.shift
if (a == 1 && a == 2 && a == 3) {
console.log('hello medium')
}
解決方案 3:使用“with”運(yùn)算符
MDN 有一個(gè)關(guān)于 with 使用的警告,好像它的存在是一個(gè)錯(cuò)誤。 我在工作中從未使用過它,但它可以用來解決這個(gè)問題。
let i = 1
with ({
get a() {
return i++
}
}) {
if (a == 1 && a == 2 && a == 3) {
console.log('hello medium')
}
}
你太聰明了,甚至不需要我解釋代碼的含義。
解決方案 4:Symbol.toPrimitive
我們可以使用隱式轉(zhuǎn)換規(guī)則3來完成問題(看完答案你就知道為什么了?。?。
const a = {
i: 1,
[Symbol.toPrimitive]() {
return this.i++
}
}
if (a == 1 && a == 2 && a == 3) {
console.log('hello medium')
}
數(shù)據(jù)劫持也是一種出路
通過隱式轉(zhuǎn)換,我們做了3個(gè)答案讓a == 1 && a == 2 && a == 3 返回true,你一定想到了另一個(gè)答案,數(shù)據(jù)劫持,偉大的Vue我們用它來贏得人心 數(shù)百萬開發(fā)者,我們也嘗試用它來解決這個(gè)面試問題。
解決方案 5:Object.defineProperty
通過劫持‘window’對象,每次讀取‘a(chǎn)’屬性時(shí),_a加1。
let _a = 1
Object.defineProperty(window, 'a', {
get() {
return _a++
}
})
if (a == 1 && a == 2 && a == 3) {
console.log('hello medium')
}
解決方案 6:代理
還有另一種劫持?jǐn)?shù)據(jù)的方式,Vue3 也用 Proxy 替換了 Object.defineProperty。
let a = new Proxy({ i: 1 }, {
get(target) {
return () => target.i++
}
})
if (a == 1 && a == 2 && a == 3) {
console.log('hello medium')
}
?