??之前在社區(qū)看到這道題時,我第一反應就是如果我在代碼庫中看到這樣的代碼我肯定是很絕望的?。。⊙詺w正傳,看到這題的時候,我首先想到的是(a == 1 && a == 2 && a==3)為true的情況(寬松匹配),我們先了解這種情況,然后在解決擴展問題。
??首先,在JS中,寬松匹配 ==會先將左右兩兩邊的值轉化成相同的原始類型,然后再去比較他們是否相等。在轉化之后(== 一邊或兩邊都需要轉化),最后的相等匹配會像 ===符號一樣去執(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ù)組轉換成字符串的時候,數(shù)組
toString會隱含調用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嗎?
答案當然是肯定的!
??但是,嚴格相等并沒有轉化的過程,所以我們需要通過一些方式去調用一個函數(shù),并在這個函數(shù)中做我們想做的事情。但是執(zhí)行函數(shù)往往需要在函數(shù)名字后引入 () ,并且由于這里不是寬松相等 ==, valueOf將不會被JS引擎調用。幸好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屬性, 我們可以調用一個函數(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 );