現代 JavaScript 程式設計教學:使用運算子 (Operator)

【分享本文】
Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email

    前言

    在程式語言中,運算子 (operator) 視為該語言基本的指令,通常不能再拆分成更小的單位。本文介紹 JavaScript 中可用的運算子。

    自製斷言 (Assertion)

    傳統上,程式語言的教材會用終端機輸出文字,再由程式撰寫者判讀。但這樣的方式並沒有充份利用到電腦程式自動化的功能,因為每次的判讀皆需要人工作業。

    比較好的方式,是透過斷言 (assertion) 來判定程式是否錯誤。所謂的斷言,是用來確認某段程式是否正確的程式碼。雖然 JavaScript 沒有內建的斷言,我們可以自己寫一個簡易版的斷言。參考以下實例:

    assert(1 + 1 === 2, "1 + 1 should be 2");
    
    // Home-made assertion.
    function assert(cond, msg) {
        if (!(cond)) {
            throw msg;
        }
    }
    

    在本例中,assert 是一個函式,該函式在 cond 不為真時,會拋出 msg 字串並中止程式運行。斷言基本上就是執行這樣的任務,我們這裡用簡易的方法來實作斷言。雖然我們還沒正式學函式的寫法,這個函式很短,可以試著讀讀看。

    代數運算子 (Arithmetic Operator)

    代數運算子 (arithmetic operator) 用來進行基本的四則運算。ECMAScript 支援以下代數運算子:

    • +:相加
    • -:相減
    • *:相乘
    • /:相除
    • %:取餘數
    • +:取正號
    • -:取負號
    • ++:遞增 (加 1)
    • --:遞減(減 1)

    代數運算子使用方式如同數學上的代數,像 2 + 3 * 5 會先運算 3 * 5 再加 2,如果要改變其順序,可用中括號,像 (2 + 3) * 5 會先計算 (3 + 5) 再乘 5。以下是使用代數運算子的實例:

    assert(3 + 4 == 7, "Wrong value");
    assert(3 - 4 == -1, "Wrong value");
    assert(3 * 4 == 12, "Wrong value");
    assert(3 / 4 == 0.75, "Wrong value");
    assert(3 % 4 == 3, "Wrong value");
    
    // Home-made assertion.
    function assert(cond, msg) {
        if (!(cond)) {
            throw msg;
        }
    }
    

    由於 JavaScript 沒有內建的斷言 (assertion),我們自製了一個簡易的版本。使用斷言取代終端機輸出,可以讓我們清楚地表達程式的意圖,也可讓程式自動進行檢查。

    由於 ECMAScript 的數字是浮點數,相除時可能會得到有小數點的數,這時候,可視需求使用 Math.round() (四捨五入)、 Math.floor() (無條件捨去) 或是 Math.ceil() (無條件進位) 取至整數位。如下例:

    assert(Math.round(4.5) === 5, "Wrong value");
    assert(Math.floor(4.5) === 4, "Wrong value");
    assert(Math.ceil(4.5) === 5, "Wrong value");
    
    // Home-made assertion.
    function assert(cond, msg) {
        if (!(cond)) {
            throw msg;
        }
    }
    

    遞增或遞減是一種語法糖,基本上就是把 x = x + 1 簡化的語法。遞增/減可以前置或後置,會影響到變數的狀態,如下例:

    let x = 4;
    
    // DON'T DO THIS in production code.
    let y = ++x + x++;
    
    assert(x === 6, "Wrong value x");
    assert(y === 10, "Wrong value y");
    
    // Home-made assertion.
    function assert(cond, msg) {
        if (!(cond)) {
            throw msg;
        }
    }
    

    在這個例子中,x 遞增兩次,故得 6yx 遞增一次後 (當下為 5) 自身疊加一次,故得 10。雖然這是合法的 JavaScript 程式,但閱讀此段程式碼的人往往需多想一下程式的狀態;筆者建議不要去強記前置或後置的規則,把遞增/減寫在單獨的一行比較好。

    比較運算子 (Relational Operator)

    比較運算子 (relational operator) 用來比較兩資料間的大小。以下是 JavaScript 的比較運算子:

    • ===:嚴格相等
    • !==:嚴格不等
    • ==:相等
    • !=:不等
    • >:大於
    • >=:大於等於
    • <:小於
    • <=:小於等於

    以下是實例:

    assert(4 > 3, "Wrong relation");
    assert(4 >= 3, "Wrong relation");
    assert(3 === 3, "Wrong relation");
    assert(5 !== 3, "Wrong relation");
    assert(3 < 4, "Wrong relation");
    assert(3 <= 4, "Wrong relation");
    
    // Home-made assertion.
    function assert(cond, msg) {
        if (!(cond)) {
            throw msg;
        }
    }
    

    JavaScript 使用兩種不同的相等/不等運算子,一般情形下,建議用嚴格相等/不等運算子,因為另一種相等/不等運算子有著複雜的隱性轉換規則 (共 23 種),與其去強記那些複雜的規則不如用比較單純的嚴格相等/不等運算子。

    字串運算子

    JavaScript 用 + 做為字串相接的運算子:

    • +:相接

    在 ECMAScript 6 以後,可以直接用字串模板 (template literal) 取代大部分的字串相接運算子。搭配 Babel 的話,可以把字串模板轉為合法的 ES5 字串,不用手動串連字串。

    邏輯運算子

    邏輯運算是用來結合多個條件時使用,有以下運算子:

    • &&:且 (and)
    • ||:或 (or)
    • !:否 (not)

    一般計算機概論的書籍會列真值表,不要特別去背誦,只要記住以下原則即可:

    • 且 (and):所有條件為真時才為真
    • 或 (or):只要其中一個條件為真時為真

    以下是實例:

    // && (and)
    assert((true && true) === true, "Wrong logic");
    assert((true && false) === false, "Wrong logic");
    assert((false && true) === false, "Wrong logic");
    assert((false && false) === false, "Wrong logic");
    
    // || (or)
    assert((true || true) === true, "Wrong logic");
    assert((true || false) === true, "Wrong logic");
    assert((false || true) === true, "Wrong logic");
    assert((false || false) === false, "Wrong logic");
    
    // ! (not)
    assert((!true) === false, "Wrong logic");
    assert((!false) === true, "Wrong logic");
    
    // Home-made assertion.
    function assert(cond, msg) {
        if (!(cond)) {
            throw msg;
        }
    }
    

    三元運算子 (Ternary Operator)

    三元運算子是較簡短的 ifelse … 語法,主要用於一行內的短敘述:

    • (condition) ? .. : ..

    由於三元運算子是表達式 (expression),會回傳值。以下是實例:

    let n = 5 > 3 ? 5 : 3;
    assert(n === 5, `Wrong value: ${n}`);
    
    // Home-made assertion.
    function assert(cond, msg) {
        if (!(cond)) {
            throw msg;
        }
    }
    

    二元運算運算子 (Bitwise Operators)

    以下是 JavaScript 的二位元運算子:

    • bitwise and &
    • bitwise or |
    • bitwise xor ^
    • bitwise not ~
    • left shift <<
    • right shift >>
    • zero-fill right shift >>>

    雖然二位元運算對一般讀者來說比較陌生,但適度地運用二位元運算可節省運算時間,以下是一個例子:

    let a = 3;  // 0000 0011
    let b = 5;  // 0000 0101
    
    /*    0000 0011
       &) 0000 0101
       -------------
          0000 0001  */
    assert((a & b) === 1, "3 & 5 should be 1");
    
    /*    0000 0011
       |) 0000 0101
       -------------
          0000 0111  */
    assert((a | b) === 7, "3 | 5 should be 7");
    
    /*    0000 0011
       ^) 0000 0101
       -------------
          0000 0110  */
    assert((a ^ b) === 6, "3 ^ 5 should be 6");
    
    // Home-made assertion.
    function assert(cond, msg) {
        if (!(cond)) {
            throw msg;
        }
    }
    

    二元運算在日常生活中不會用到,有些讀者可能會對二元運算感到陌生,筆者在註解處寫下運算過程,供讀者參考。如果讀者想學二元運算,可以翻閱計算機概論等書籍,此處不詳談。

    型別檢查運算子

    JavaScript 使用 typeof 做為型別運算子,typeof 會回傳一個字串,該字串表示資料的型別,可能的回傳值如下:

    • “undefined”
    • “boolean”
    • “number”
    • “string”
    • (新) “symbol”
    • “function”
    • “object”

    由於 JavaScript 的物件系統是以原型 (prototype) 為基礎,物件沒有類別 (class) 的概念,我們無法用 typeof 來檢查物件的型別,程式設計者需要改變對物件的思維。我們將於後文說明 JavaScript 的物件系統。

    指派運算子 (Assignment Operators)

    指派運算子算是一種語法糖,將 x = x + 1 簡化為 x += 1,大部分的代數運算子和二元運算子都有相對應的指派運算子:

    • +=
    • -=
    • *=
    • /=
    • %=
    • <<=
    • >>=
    • >>>=
    • &=
    • |=
    • ^=

    (新) 解構運算 (Destructing Assignment)

    解構運算是 ECMAScript 6 之後所加入的新功能,主要是簡化從物件中取出資料的過程;雖然不是必備的特性,但的確可以縮減一些程式碼,如下例:

    const obj = {b: 2, c: 3, d: 4};
    
    // Destructing assignment.
    const {a, b, c} = obj;
    
    assert(typeof a === "undefined", "a should be undefined");
    assert(b === 2, "b should be 2");
    assert(c === 3, "c should be 3");
    
    // Home-made assertion.
    function assert(cond, msg) {
        if (!(cond)) {
            throw msg;
        }
    }
    

    在這個例子中,a 沒有值,故為未定義的 (undefined),bc 則各自指派到特定值。

    【分享本文】
    Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email
    【追蹤新文章】
    Facebook Twitter Plurk