a 可以同時 == 1 && == 2 && == 3嗎

此題目的答案可以分為三大類:

1. 類型轉換時的劫持

首先我們要知道,在 JS 中類型轉換只有三種情況,分別是:

  • 轉換為布爾值

  • 轉換為數字

  • 轉換為字符串

轉換為原始類型
對象在轉換類型的時候,會執行原生方法ToPrimitive。

其算法如下:

1.如果已經是 原始類型,則返回當前值;

2.如果需要轉 字符串 則先調用 toSting方法,如果此時是 原始類型 則直接返回,否則再調用 valueOf方法并返回結果;

3.如果不是 字符串,則先調用 valueOf方法,如果此時是 原始類型 則直接返回,否則再調用 toString方法并返回結果;

4.如果都沒有 原始類型 返回,則拋出 TypeError類型錯誤。

當然,我們可以通過重寫 Symbol.toPrimitive來制定轉換規則,此方法在轉原始類型時調用優先級最高。

所以以此定義我們可以有以下四種答案:

var a = {arr: [3,2,1],

            valueOf() {
                console.group('valueOf')
                console.log(this.arr)
                console.groupEnd('valueOf')
                return this.arr.pop()
            }
        }
    if (a == 1 && a == 2 && a == 3) {
        console.log('biu')
    }
    var b = {arr: [3, 2, 1],
            toString() {
                console.group('toString')
                console.log(this.arr)
                console.groupEnd('toString')
                return this.arr.pop()
            }
        }
    if (b == 1 && b == 2 && b == 3) {
        console.log('biu')
    }
    var c = {arr: [3, 2, 1],
            [Symbol.toPrimitive]() {
                console.group('Symbol.toPrimitive')
                console.log(this.arr)
                console.groupEnd('Symbol.toPrimitive')
                return this.arr.pop()
            }
        }
    if (c == 1 && c == 2 && c == 3) {
        console.log('biu')
    }
    var d = [1, 2, 3]
    d.join = d.shift
    if (d == 1 && d == 2 && d == 3) {
        console.log('biu')
    }
   

注:事實上,這四種可以算是同一種。關于最后一種,我們可以來看看ECMA中的 Array.prototype.toString() 定義:

1.定義 array 為 ToObject(thisvalue)(原生方法,將當前數組轉換成對象);

2.定義 func 為 Get(array,'join')(原生方法,在這一步調用 join 方法);

3.如果 IsCallble(func) (原生方法,判斷是否有內部可調用的函數)為 false,則 設置 func 原生函數 %ObjProto_toString%(原生函數, toString 的具體實現);

4.返回 Call(func,array)。

2. 對 getter 的劫持

所謂的 getter 就是對象屬性在進行查詢時會被調用的方法 get,利用此函數也可以實現題目功能。

代碼如下:

window.val = 0

    Object.defineProperty(window, 'd', {
        get() {
            return ++this.val
        }
    })

    if (d == 1 && d == 2 && d == 3) {
        console.log('biu')
    }
    
    const e = new Proxy({}, {
        val: 1,
        get ()  {
            return () => this.val++;
        }
    });

    if (e == 1 && e == 2 && e == 3) {
        console.log('biu')
    }

3. 正則表達式

JS 中的 RegExp.prototype.exec() 作用是在一個指定字符串中執行一個搜索匹配,返回一個結果數組或 null。

當正則表達式使用 " g" 標志時,可以多次執行 exec 方法來查找同一個字符串中的成功匹配。當你這樣做時,查找將從正則表達式的 lastIndex 屬性指定的位置開始。( test() 也會更新 lastIndex 屬性)。

lastIndex 是正則表達式的一個可讀可寫的整型屬性,用來指定下一次匹配的起始索引。只有正則表達式使用了表示全局檢索的 " g" 標志時,該屬性才會起作用。

注:只有正則表達式使用了表示全局檢索的 " g" 標志時,該屬性才會起作用。

綜上所述,我們可以有方案如下:

var f = {
        reg: /\d/g,
        valueOf () {
            return this.reg.exec(123)[0]
            }
        }

    if (f == 1 && f == 2 && f == 3) {
        console.log('biu')
    }
    

注:上述方法其實也利用了類型轉換的特點。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容