【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
の値にnull
やundefined
が設定されている場合、デフォルトでは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 } }