厳格モード
メモ: デフォルトの厳格でないモードを sloppy モード と呼ぶのを目にすることがあるかもしれません。これは公式な用語ではありません、念のため注意してください。
JavaScript の厳格モード (Strict mode) は、 JavaScript の自由度を制限することにオプトインすることによって、暗黙のうちに「sloppy モード」からオプトアウトする方法です。厳格モードは単なるサブセットではなく、通常のコードとは意図的に異なる意味を持っています。厳格モードのコードと非厳格モードのコードは共存できますので、スクリプトを順次厳格モードにオプトインすることができます。
厳格モードでは、通常の JavaScript の意味にいくつかの変更を加えます。
- JavaScript で暗黙に失敗する一部のものを、エラーが発生するように変更することで除去します。
- JavaScript エンジンによる最適化処理を困難にする誤りを修正します。厳格モードのコードは、非厳格モードのコードより高速に実行できる可能性があります。
- 将来の ECMAScript で定義される予定の構文の使用を禁止します。
厳格モードの呼び出し
厳格モードはスクリプト全体または個別の関数に適用できます。中括弧 {} で括られるブロック構文には適用できません。そのような場所に適用しようとしても何も起きません。eval のコード、 Function のコード、イベントハンドラー属性、setTimeout() などの関数に渡す文字列は、関数の本体またはスクリプト全体であり、厳格モードを呼び出すと期待どおりに動作します。
スクリプトでの厳格モード
スクリプト全体で厳格モードを呼び出すには、他のいかなる文よりも前に "use strict"; (または 'use strict';) という文をそのまま追加します。
// スクリプト全体の厳格モード構文
"use strict";
const v = "こんにちは!厳格モードのスクリプトです!";
関数における厳格モード
同様に、関数で厳格モードを呼び出すには、関数本体で他のいかなる文よりも前に "use strict"; (または 'use strict';) という文をそのまま追加します。
function myStrictFunction() {
// 関数レベルの厳格モード構文
"use strict";
function nested() {
return "私もそうです!";
}
return `こんにちは!厳格モードの関数です! ${nested()}`;
}
function myNotStrictFunction() {
return "厳格モードではありません。";
}
"use strict" ディレクティブは、単純な引数を持つ関数の本体にのみ使用することができます。"use strict" を残余、デフォルト、構造分解引数のある関数で使用すると、構文エラーとなります。
function sum(a = 1, b = 2) {
// SyntaxError: "use strict" not allowed in function with default parameter
"use strict";
return a + b;
}
モジュールでの厳格モード
JavaScript モジュールは内容全体が自動的に厳格モードになり、それを開始するための宣言は必要ありません。
function myStrictFunction() {
// これはモジュールなので、デフォルトで厳格モードです
}
export default myStrictFunction;
クラスでの厳格モード
クラス本体のすべての部分は、クラス宣言でもクラス式でも、厳格モードのコードになります。
class C1 {
// ここにあるコードはすべて厳格モードで評価されます
test() {
delete Object.prototype;
}
}
new C1().test(); // TypeError。 test() が厳格モードであるため
const C2 = class {
// ここにあるコードはすべて厳格モードで評価されます
};
// このコードは厳格なモードでない可能性があります。
delete Object.prototype; // エラーは発生しない
厳格モードでの変更点
厳格モードでは構文と実行時動作の両方に変更を加わります。変更点は以下のカテゴリーに分類されます。
- ミスからエラー (構文エラーまたは実行時エラー) への変換
- 与えられた名前から特定の変数を算出する方法の単純化
evalおよびargumentsの単純化- 「安全な」 JavaScript を書くことの容易化
- 将来の ECMAScript の進化への事前対処
ミスからエラーへの変換
厳格モードでは、従来は受け入れていた一部のミスをエラーに変更します。JavaScript は未熟な開発者にも易しいように設計され、またエラーとすべき操作の一部をエラーとして扱いません。これにより当面の問題を解決したことがありますが、後により大きな問題を引き起こしたこともあります。厳格モードではこれらのミスをエラーとして扱うことで、開発者が気づいて修正できるようになります。
未宣言の変数への代入
厳格モードでは、偶発的にグローバル変数を作成できないようにします。厳格モードでない場合は、代入文で変数名の綴りを間違えるとグローバルオブジェクトに新しいプロパティが作成され、そしてそれは動作し続けます。厳格モードでは、代入文で偶発的にグローバル変数を作成せずにエラーが発生します。
"use strict";
let mistypeVariable;
// グローバル変数 mistypeVarible が存在しない場合、
// この行は "mistypeVariable" のスペルミス
// ("a" がない)と見なして ReferenceError を発生させます。
mistypeVarible = 17;
オブジェクトプロパティへの代入の失敗
厳格モードでは、特定の代入文では暗黙的に失敗せずにエラーが発生します。プロパティの代入を失敗させる方法は 3 つあります。
- 書き込み不可のデータプロパティへの代入
- アクセサーがゲッターのみであるプロパティへの代入
- 拡張不可のオブジェクトにおける新しいプロパティへの代入
例えば、NaN は書き込み不可のグローバル変数です。厳格モードでない場合は、 NaN に代入しても何も起きません。つまり、開発者は失敗したという通知を受けません。厳格モードでは NaN に代入すると例外が発生します。
"use strict";
// 書き換え不可能なグローバルへの代入
undefined = 5; // TypeError
Infinity = 5; // TypeError
// 書き換え不可能なプロパティへの代入
const obj1 = {};
Object.defineProperty(obj1, "x", { value: 42, writable: false });
obj1.x = 9; // TypeError
// ゲッターのみのプロパティへの代入
const obj2 = {
get x() {
return 17;
},
};
obj2.x = 5; // TypeError
// 拡張不可能なオブジェクトの新しいプロパティへの代入
const fixed = {};
Object.preventExtensions(fixed);
fixed.newProp = "ohai"; // TypeError
オブジェクトプロパティの削除の失敗
厳格モードでは、削除操作を構成不可、またはその他の理由で削除できないプロパティ(例えば、プロキシーの deleteProperty ハンドラーが false を返すことで妨害されるもの)に対して試みると、例外が発生します(以前は何も起きませんでした)。
"use strict";
delete Object.prototype; // TypeError
delete [].length; // TypeError
厳格モードでは、素の名前を削除することも禁じられています。 delete name は厳格モードでは構文エラーになります。
"use strict";
var x;
delete x; // syntax error
名前が設定可能なグローバルプロパティの場合、それを削除するには