JavaScript騷操作之操作符

黑金團隊發表於2018-12-16

三目運算子 ?:

每到週末我都會問自己,怎麼安排?於是我寫了個程式跑了一下

    if (hasMoney) {
        console.log('週末嗨翻天');
    } else {
        console.log('週末睡一天');
    }
複製程式碼

看上去沒有什麼問題,但總感覺程式碼有點臃腫,能不能稍微簡約一點?

換成三目運算子後

    hasMoney ? console.log('週末嗨翻天') : console.log('週末睡一天');
複製程式碼

look,當hasMoney為true的時候,嗨翻天,為false的時候的睡一天。這種操作符在我們的根據簡單的判斷條件賦值的時候非常有用

    let weekendPlan = hasMoney ? '週末嗨翻天' : '週末睡一天';
複製程式碼

如此,我們的程式碼就不會充斥著大量的if判斷條件句,還能略顯騷氣。但是,別騷過度了

    val = simpleCondition
        ? 1
        : simpleConditionAgain
        ? 2
        : simpleConditionAgainAndAgain
        ? 3
        : 4;
複製程式碼

上面的例子有點為了裝逼而裝逼的感覺,在程式碼可讀性方面有點糟糕,即使換成了if條件句也不甚美觀;像這種情況,可以使用switch語句或者策略模式的設計思想優化。

邏輯與操作符 &&

如果有錢的話,週末就去嗨翻天,但沒錢的情況還沒有想好要幹嘛(雖然沒錢的情況幹不了什麼),常規操作為

    if (hasMoney) {
        console.log('週末嗨翻天');
    }
複製程式碼

這個時候使用三目運算子改寫的話

    hasMoney ? console.log('週末嗨翻天') : undefined;
複製程式碼

有點奇怪,我們不得不寫個undefined去告訴程式判斷條件為false的時候應該怎麼做。使用邏輯與操作符就可以避免這個問題

    hasMoney && console.log('週末嗨翻天');
複製程式碼

邏輯與操作符會使用Boolean函式判斷每一個條件(表示式)是否為true,當所有的判斷條件都為true的情況下,就會返回最後的表示式的運算結果;但是如果有判斷條件為false的話,就會返回第一個判斷條件為false的運算結果

    true && console.log('It is true');                         // It is true
    true && false && console.log('It is true');                // 返回 false
    true && 0 && console.log('It is true');                    // 返回 0
    true && undefined == null && console.log('It is true');    // It is true, 表示式undefined == null的運算結果為true
    true && undefined === null && console.log('It is true');   // 返回 false, 表示式undefined === null的運算結果為false
複製程式碼

所以在react中使用邏輯與操作符渲染元素的時候,一定要注意

    render() {
        return (
            <Fragment>{
                data.length && data.map(item => <span>{ item }</span>)
            }</Fragment>
        );
    }

    // 當沒有資料的時候,頁面會渲染出一個0
複製程式碼

上面的例子的本意是當有資料的時候就將資料渲染出來,沒有資料的時候,不做任何操作。但是邏輯與操作符會將第一個為false的表示式的運算結果返回,導致返回了個0!

邏輯或操作符 ||

說到邏輯與操作符,就不得不提它的好基友:邏輯或操作符。考慮下面的場景

    // 當自身為undefined時,賦值為0,否則還是賦值為自身
    val = val !== undefined ? val : 0;
複製程式碼

使用三目運算子去處理上述例子的邏輯時,我們需要顯式的判斷val是否為空的,然後再決定變數val是否應該等於本身。那麼本著能省就省的原則,我們可以使用邏輯或操作符

    val = val || 0;
複製程式碼

邏輯或操作符,其會將第一個表示式的運算結果傳入Boolean函式,如果Boolean函式返回true,就會返回這個運算結果;否則將會嘗試下一個,直到結束;如果所有的表示式的運算結果對應的布林值都為false,則返回最後一個表示式的運算結果

故此操作符在向下相容、設定函式引數的預設值時非常有用

    // ES5設定函式預設值
    function testFunc(arg1) {
        arg1 = arg1 || 1;

        // do something else
    }

    let a = 1,
        b = 2,
        c = null;
    
    console.log(a || b || c);         // 1
    console.log(0 || b || c);         // 2
    console.log(0 || false || c);     // null
複製程式碼

note: 故此猜想,if條件句裡面使用邏輯或、邏輯與操作符,實際上也只是返回表示式的運算結果,然後再隱式呼叫了Boolean函式得到一個最終的布林值

邏輯取反 !

上文說到,有錢的週末可以為所欲為,沒錢的週末,估計也就只能選擇睡一天了。這種情況下,如果使用hasMoney作為判斷標準,我們的程式碼是這樣的

    hasMoney === false && console.log('週末睡一天');
複製程式碼

當hasMoney不是一個布林值的時候,hasMoney === false語句就會一直返回false,造成有錢的假象。所以我們必須的將hasMoney轉換成一個布林值才能判斷,恰好取反操作符可以同時給我們做這兩件事

    !hasMoney && console.log('週末睡一天');
複製程式碼

這樣就能在沒錢的時候睡一天了。

取反操作符能夠將一個非Boolean型別的值轉化為Boolean型別的值且取反

    !true && console.log('666');             // 返回false
    !!true && console.log('666');            // 666
    {} && console.log('666');                // 報錯
    !{} && console.log('666');               // 返回false
    !!{} && console.log('666');              // 666
複製程式碼

按位取反操作符 ~

加入我們需要判斷一個陣列裡面是否存在某個元素,在ES6裡面可以使用includes

    let arr = ['we', 'are', 'the', 'BlackGold', 'team'];

    arr.includes('the') && console.log('in');      // in
複製程式碼

但是這個方法有比較大的限制:沒辦法傳入一個篩選函式。

    let arr = ['we', 'are', 'the', 'BlackGold', 'team'];

    arr.includes(element => element === 'the') && console.log('in');     // 返回false
複製程式碼

這種情況下,我們通常可以使用findIndex方法

    let arr = ['we', 'are', 'the', 'BlackGold', 'team'];

    arr.findIndex(element => element === 'the') !== -1 && console.log('in');      // in
複製程式碼

由於findIndex方法返回的索引是從0開始的,所以我們必須得判斷其返回的索引是否不等於-1或者是大於等於0。如果使用按位取反操作符,將不需要顯示去判斷

    let arr = ['we', 'are', 'the', 'BlackGold', 'team'];

    ~arr.findIndex(element => element === 'we') && console.log('in');      // in
    ~arr.findIndex(element => element === 'the') && console.log('in');      // in
複製程式碼

按位取反操作符,顧名思義,就是將變數的每一個位元位取反:0->1、1->0

    console.log(~-1);       // 0 轉換為Boolean值即為false
    console.log(~0);        // -1 轉換為Boolean值即為true
    console.log(~1);        // -2 轉換為Boolean值即為true
複製程式碼

結語

JavaScript騷操作系列主要總結JavaScript一些好用的特性、方法,以供交流學習之用,不喜勿噴。如有錯漏,歡迎指正。

相關文章:

JavaScript騷操作之遍歷、列舉與迭代(上篇)

JavaScript騷操作之遍歷、列舉與迭代(下篇)

@Author: PaperCrane

相關文章