Works by

Works by

プログラミング等IT技術関連でメモする

【JavaScript】Strictモード

strict モードとは

Strictモードとは、JavaScript上で文法的に誤りではないが開発者にとって落とし穴となるような
コードを、エラーが発生するように変更するオプションです。

strictモードにするとうれしいこと

  • JavaScript上でバグの温床となりやすい記述を構文解析時点で回避できる

  • javaScriptエンジンが最適化しにくい記述が修正され、高速実行できる可能性が高まる

  • 将来、ECMAScriptが実装予定の予約語を含む構文を使用禁止にできる

使い方

strictモードの範囲には二種類が指定できます。

スクリプト全体に適用

"use strict";

//
// other code.
//

スクリプト上部に記述することで、記述されたスクリプトファイル全体にstrictモードの設定が適用されます。

関数スコープ内に適用

function strict(){
        "use strict";
        // other code.
}

関数スコープ内のトップに記述することで、そのスコープ内でstrictモードの設定を適用できます。

strictモードによる制約項目

1. アンチパターンのエラー化

グローバル変数の禁止

"use strict";

// Reference Error をスロー
globalVar = "Global"; 

グローバル変数の定義を禁止します。
グローバル変数による名前空間の汚染(グローバル汚染)を防ぎます。

書き込み不可プロパティへの代入を禁止

"use strict";

let obj = {};
Object.defineProperty(obj, "x", {value:42, writable: false});
// Type Error をスロー
obj.x = 10;

オブジェクトのプロパティ定義時にwritableプロパティをfalseにすると、
プロパティへの書き込み時にエラーが発生します。

削除不可プロパティの削除禁止

"use strict";

// Type Error をスロー
delete Object.prototype;

オブジェクトの削除不可プロパティをdeleteで削除不可にします。

プロパティ名の重複を禁止

"use strict";

// Syntax Error をスロー
let obj = { value: 1, value: 2 };

オブジェクトに同じ名前のプロパティで複数の値を設定した場合、
最後に記述した定義が反映されます。
strictモードでは、同じ名前のプロパティ記述自体を禁止します。

関数引数名の重複を禁止

// Syntax Error をスロー
function hoge(x,x,x){
        "use strict";
}

プロパティ名同様、関数の引数名の重複も禁止します。

8進数表記の禁止

"use strict";

// Syntax Error をスロー
let value = 012;

整数の頭に0をつけることを禁止します。
表記上の理由から整数の頭に0をつけてしまった上で、10進数と誤解してしまう・・・等のヒューマンエラーを防ぐためです。

2. 変数使用の単純化

with文の禁止

"use strict";

let x = 10;

// Syntax Error をスロー
with (obj) {
        console.log(x)
}

withの使用そのものを禁止します。
withに渡されたオブジェクトのプロパティ名とブロック外の変数の名前が被り、
参照先を見誤ってしまうのを防ぎます。

eval関数で実行するコード中の変数はeval内に閉じる

"use strict";

eval("let x = 10;")

// Reference Error をスロー
console.log(x); 

evalによって実行されたコード内の変数スコープが、
evalコード内となります。

eval関数で実行するコードはstrictモードになる

"use strict";

// strict mode
eval("var x = 10;")

strictモードでeval関数を実行した場合、
eval関数が実行したコードもstrictモードで解析されます。

単純名削除を禁止

"use strict";

let x;
delete x;

既に宣言された名前の削除を禁止します。

3. eval/argumentsの単純化

eval/argumentsの名前に対するバインド・代入を禁止

"use strict";

// 以下全てエラー
eval = 10;
arguments = 5;

eval++;
arguments++;

var eval;
var arguments;

function f(eval){};
function g(arguments){};

var func = function eval(){};
var y = function arguments(){};

eval/argumentsを変数や引数として使うことを禁止します。 eval/argumentsを書き換えた上での参照先の誤解がなくなります。

関数引数への変更がargumentsに反映されなくなる

function f(arg){
        "use strict";
        arg = 20;

        console.log(arguments[0]); // 10
}
f(10);

関数内で参照できるargumentsを使うことで、呼び出した関数の引数にアクセスできます。
デフォルトでは、関数の引数を書き換えることでargumentsにも変更が及びますが、
strictモードではargumentsが変更しなくなります。

arguments.callee をサポートしなくなる

function f(n){
        "use strict";

        if (n > 0) {  
            // Type Error をスロー
            return n + arguments.callee(n-1)
        }
}

現在コールされている関数への参照arguments.calleeが使用不可能になります。

4. JavaScriptのセキュア化

thisのnull/undefined時の挙動

function f(n){
        "use strict";

        // true
        if (!this) {
            this = 'pen';
            console.log("'this' is a pen."); // 'this' is a pen.
        }
}

関数内で呼び出すthisには、関数を呼び出したオブジェクトへの参照が保持されています。
thisの値にnullundefinedが設定されている場合、デフォルトではthisがグローバルオブジェクトとなりますが、 strictモードではnull/undefinedのままになります。

thisの参照先がデフォルトのグローバルオブジェクトとならないことで、
例えばif文でthisのfalsyチェックなどを行う場合にミスが起こりにくくなります。

関数内での[関数名].caller/argumentsの呼び出し禁止

function f(){
        "use strict";

        // Type Error をスロー
        f.caller;
        f.arguments;
}

関数名からcaller/argumentsを呼び出すことによる、
関数や引数へのアクセスを禁止します。

これにより、argumentsによって参照できる引数の情報は、
原則argumentsの予備元の関数の引数のみとなります。

arguments経由のcaller呼び出し禁止

function f(){
        "use strict";

        // Type Error をスロー
        arguments.caller;
}

callerはargumentsのプロパティでもあります。
strictモードでは、このアクセスも禁止します。

5. 今後のECMAScriptに合わせた制約

スクリプトトップレベルのfunctionを禁止

"use strict";

function parent(){
        function child(){
            // Syntax Error
        }
}

if(true){
        function child(){
            // Syntax Error
        }
}

for(var i = 0; i < 10; i++){
        function child(){
            // Syntax Error
        }
}

注意点

参考文献

厳格モード (JavaScript)

Strict モード - JavaScript | MDN