??之前在社區(qū)看到這道題時弄屡,我第一反應就是如果我在代碼庫中看到這樣的代碼我肯定是很絕望的L赓鳌!膀捷!言歸正傳迈嘹,看到這題的時候,我首先想到的是(a == 1 && a == 2 && a==3)
為true的情況(寬松匹配),我們先了解這種情況,然后在解決擴展問題秀仲。
??首先融痛,在JS中,寬松匹配 ==
會先將左右兩兩邊的值轉(zhuǎn)化成相同的原始類型神僵,然后再去比較他們是否相等雁刷。在轉(zhuǎn)化之后(==
一邊或兩邊都需要轉(zhuǎn)化),最后的相等匹配會像 ===
符號一樣去執(zhí)行判斷保礼。
??那么沛励,我們考慮到的應該是a應該是什么類型,在a==
**的時候發(fā)生了什么炮障?再去考慮a應該等于什么目派。
- 如果a是一個對象Object,那在執(zhí)行a
==
的時候首先會去先執(zhí)行valueOf
方法胁赢,如果沒有valueOf
方法企蹭,就會去執(zhí)行toString
方法。(toString
方法與valueOf
類似智末,這里不再重復)
const a = { value: 0 }
a.valueOf = function () {
return this.value += 1
}
console.log( a == 1 && a == 2 && a == 3 );
- 如果a是一個數(shù)組Array谅摄,在數(shù)組轉(zhuǎn)換成字符串的時候,數(shù)組
toString
會隱含調(diào)用join()
方法
const a = [1, 2, 3];
a.join = a.shift;
console.log( a == 1 && a == 2 && a ==3 );
??那么系馆,(a === 1 && a === 2 && a === 3)
的值也能是true嗎送漠?
答案當然是肯定的!
??但是它呀,嚴格相等并沒有轉(zhuǎn)化的過程螺男,所以我們需要通過一些方式去調(diào)用一個函數(shù),并在這個函數(shù)中做我們想做的事情纵穿。但是執(zhí)行函數(shù)往往需要在函數(shù)名字后引入 () 下隧,并且由于這里不是寬松相等 ==
, valueOf
將不會被JS引擎調(diào)用谓媒。幸好Object提供了一個Property
函數(shù), 特別是getter
描述符淆院, 帶來了解決這個問題的辦法。
var value = 0; //window.value
Object.defineProperty(window, "a", {
get: function () {
return this.value += 1
}
})
console.log( a === 1 && a === 2 && a === 3 );
??上面代碼中句惯,我們在window對象上定義了一個具有getter
的 a 屬性, 通過get
屬性, 我們可以調(diào)用一個函數(shù)并且不用在函數(shù)名后添加 ()土辩,所以 a 可以在代碼中直接被訪問到(全局變量), 因此也可以直接獲得a的值抢野。如果我們在其他對象上定義了屬性 a 而不是window的話拷淘,例如object1, 我們就需要改變題目為 object1.a === 1 && object1.a === 2 && object1.a === 3
了指孤。
??擴展:字符編碼實現(xiàn)相同效果
var a? = 1;
var a = 2;
var ?a = 3;
console.log(a? === 1 && a === 2 && ?a=== 3 );