JavaScript Strict Mode

語意上的修正:

  1. Slient Error → Throw Actual Error。
  2. 修正會影響 JavaScript 引擎最佳化的錯誤 (Mistake)。有時程式在 Strict Mode 執行效率較高。
  3. 禁用未來可能會被加入 ECMAScript 的語法作為變量/屬性/function 名稱。

優點

  1. Securing JavaScript。

    Strict mode makes it easier to write "secure" JavaScript. Some websites now provide ways for users to write JavaScript which will be run by the website on behalf of other users. JavaScript in browsers can access the user's private information, so such JavaScript must be partially transformed before it is run, to censor access to forbidden functionality. JavaScript's flexibility makes it effectively impossible to do this without many runtime checks. Certain language functions are so pervasive that performing runtime checks has a considerable performance cost. A few strict mode tweaks, plus requiring that user-submitted JavaScript be strict mode code and that it be invoked in a certain manner, substantially reduce the need for those runtime checks.

  2. 為未來版本的 ECMAScript 做準備。

使用方式

  1. 在文件上寫 "use strict",作用於全文件內。

    • 如果同時引用 a.jsb.js,僅在 a.js 撰寫 "use strict",且 a.j 引用先於 b.js,strict mode 僅作用於 a.js 內。

    • This syntax has a trap that has already bitten a major site: it isn't possible to blindly concatenate non-conflicting scripts. Consider concatenating a strict mode script with a non-strict mode script: the entire concatenation looks strict! The inverse is also true: non-strict plus strict looks non-strict. Concatenation of strict mode scripts with each other is fine, and concatenation of non-strict mode scripts is fine. Only concatenating strict and non-strict scripts is problematic. It is thus recommended that you enable strict mode on a function-by-function basis (at least during the transition period).

  2. 在 function scope 寫 "use strict",作用於 function scope 內。

  3. Module 必為 strict mode

    //宣告先於 use strict, 因此不會報錯
    var let = 1;
    
    "use strict";
    
    //宣告後於 use strict, 因此報錯
    var class = 2;
    

FEATURES

Properties and Variables

  1. 不可設定值給未宣告的變數。

    "use strict";
    
    //Throw ReferenceError
    a = 123;
    
  2. 不可賦值給 non-writable 的變數/屬性。

    "use strict";
    
    let idCard = {
        name: "許祐誠"
    };
    Object.defineProperty(idCard, "num", {
        value: "ABCD1234",
        writable: false
    });
    
    //Throw TypeError
    idCard.num = "BBB";
    
  3. 不可 delete undeletable 的變數/屬性。

    • Prototype
  4. 以 literal 方式宣告 Object 時,其中的屬性名稱不可重複。

    "use strict";
    
    //Throw Error
    const person1 = {
        name: "Maw",
        name: "Arren"
    }
    
  5. function 的 parameter name 必須為唯一。

    "use strict";
    
    //Throw Error
    function hello(name, name) {
        //...
    }
    
  6. 不可設定屬性給 Primitive Value。

    "use strict";
    
    var idCard = 12345;
    
    //Throw TypeError
    idCard.name = "許祐誠"
    
  7. 不可使用 syntax (包括未來的 ECMAScript syntax) 關鍵字作為變量/屬性名稱。

    • argumentsevalclassconstlet⋯等。

Syntax

  1. 0*"\*" 的 octal syntax 禁用,須改用 ECMAScript 5 的 0o-* syntax。

    • "\045" === "%"0o045 === "%"
  2. 禁用 with syntax。

  3. eval 不添加變量至 scope。

    • eval 自成一個 Block {}
    //Sloppy Mode
    var x = 17;
    eval("var x = 42;");
    //Result is false;
    console.log(x === 17);
    
    //Strict Mode
    "use strict";
    
    var x = 17;
    eval("var x = 42;");
    //Result is true;
    console.log(x === 17);
    
  4. 不能 delete plain names。

    "use strict";
    
    var a = "A";
    //Throw SyntaxError
    delete a;
    
    function testDelete() {
        var b = "A";
        //Throw SyntaxError
        delete b;
    }
    

function 中的 arguments

  1. 不可 delete arguments

  2. 在 function 中,如果參數在 scope 內被修改了,其相對應的 arguments 不會跟著修改。

    "use strict";
    
    function hello (name) {
        name = "Maw";
        
        console.log(`Hello, ${name} (name)`);
        console.log(`Hello, ${arguments[0]} (arguments[0])`)
    }
    
    hello("Arren");
    
    //Hello, Maw (name)
    //Hello, Arren (arguments[0])
    
  3. 不支援 arguments.callee

    • arguments.callee:當前正在執行的 function 本身。
  4. 不支援 arguments.caller

Logic

  1. 當 function 與 nullBooleanundefined 進行綁定時(callapplybind);或 function 屬於 global scope 時, function 的 thisnull

    "use strict";
    
    function testThis() {
        return this;
    }
    
    testThis();//回傳 null
    testThis.call(false);//回傳 null
    testThis.call(true);//回傳 null
    testThis.apply(null);//回傳 null
    testThis.bind(undefined)();//回傳 null
    
  2. 不可在判斷語句中宣告 function (測不出來)

    "use strict";
    
    if (true) {
        //SyntaxError
        function f() {}
        
        f();
    }
    
    for (let i = 0; i < 5; i++) {
        //SyntaxError
        function f() {}
        
        f();
    }