この記事は編集レビューを必要としています。ぜひご協力ください。
この翻訳は不完全です。英語から この記事を翻訳 してください。
ECMAScript第5版では、すべての主要なブラウザ(IE10を含む)で今実装されているstrict modeが導入されています。Webブラウザが厳密であるとコードを解釈するのは簡単である一方(ソースコードの先頭に"use strict";
を追加するだけです)、strictモードに既存のコードベースを移行することは、もう少し作業が必要です。
この記事では、開発者のためのガイダンスを提供することを目的とします。
段階的移行
strictモードは設計されているます。そのため、移行は段階的に実施されます。個別に各ファイルを変更し、関数の粒度までstrictモードにコードを移行することが可能です。
非strictとstrictの違い
構文エラー
"use strict";
を追加するとき、スクリプトが実行される前に、次のケースではSyntaxError
をスローします。:
- 8進数構文
var n = 023;
with
ステートメント- 変数名での
delete
の使用delete myVariable
; - 変数または関数の引数名として
eval
またはarguments
の使用 - (第6版以前での)新しいreserved keywordsの使用:
implements
,interface
,let
,package
,private
,protected
,public
,static
, andyield
- ブロック内での関数の宣言
if(a<b){ function f(){} }
- 明らかなエラー
- オブジェクトリテラルでプロパティ名に同じ名前を2回宣言
{a: 1, b: 3, a: 7}
これはECMAScript第6版ではこのケースはもはや存在しません(バグ 1041128)。 - 同じ名前の2つの関数の引数の宣言
function f(a, b, b){}
- オブジェクトリテラルでプロパティ名に同じ名前を2回宣言
これらのエラーは良いです。というのも、それらは、プレーンエラーや不正な慣行を明らかにしました。コードが実行される前にそれらは、発生します。
新しいランタイムエラー
何かが行われた状況で静かに失敗するように使用されるJavaScriptは誤りでした。strict モードはそのような場合にスローします。コードベースは、このようなケースが含まれている場合、テストは必ず何も壊れていないと確信していることです。もう一度、それは機能の粒度レベルで発生する可能性があります。
宣言されていない変数に値を設定します
function f(x){ "use strict"; var a = 12; b = a + x*35; // error! } f();
これはめったに期待される効果はないグローバルオブジェクトの値を変更するために使用されます。本当にグローバルオブジェクトに値を設定したい場合は、それを引数として渡し、明示的にプロパティとして割り当てます:
var global = this; // in the top-level context, "this" always // refers to the global object function f(){ "use strict"; var a = 12; global.b = a + x*35; } f();
非構成可能なプロパティを削除しようとする
"use strict"; delete Object.prototype; // error!
非strictモードでは、これは静かにユーザの期待と矛盾で失敗します。
ポイズン引数と関数プロパティ
arguments.callee
, arguments.caller
, anyFunction.caller
, またはanyFunction.arguments
にアクセスするとstrictモードではエラーをスローします。唯一の合法的なユースケースは、のような機能を再利用することであろう:
// example taken from vanillajs: https://vanilla-js.com/ var s = document.getElementById('thing').style; s.opacity = 1; (function(){ if((s.opacity-=.1) < 0) s.display="none"; else setTimeout(arguments.callee, 40); })();
上記は以下のように書き換えられます。:
"use strict"; var s = document.getElementById('thing').style; s.opacity = 1; (function fadeOut(){ // name the function if((s.opacity-=.1) < 0) s.display="none"; else setTimeout(fadeOut, 40); // use the name of the function })();
意味の違い
これらの違いは非常に微妙な違いです。テストスイートはこの種の微妙な差をキャッチしていない可能性があります。コードベースを慎重に見直し、おそらくこれらの違いは、コードの意味に影響を与えないことを確認するために必要になります。幸いなことに、この慎重な検討によって、関数の粒度を徐々に下げることができます。
関数呼び出しでのthis
f()
のような関数呼び出しで、this
値はグローバルオブジェクトでした。strictモードでは、今undefined
です。関数がcall
または apply
で呼び出されるとき、値がプリミティブな値であった場合、これはオブジェクト(または、undefined
やnull
に対してはグローバルオブジェクト)にボックス化されました. strictモードでは、値は、変換または交換せずに直接渡されます。
arguments
名前付きの関数の引数をエイリアスしない
非strictモードでは、arguments
オブジェクト内の値を更新すると、対応する名前付きの引数を更新します。これはJavaScriptエンジンのための複雑な最適化を行い、読み/理解しにくいコードを作りました。strictモードでは、arguments
オブジェクトは名前付き引数と同じ値で生成され初期化されています。しかし、arguments
オブジェクトか名前付きの引数への変更はお互いに反映されていません。
eval
への変更
strictモードコードでは、eval
は呼び出される範囲で新しい変数を生成しません。また、strictモードでは、もちろん、文字列はstrictモードのルールで評価されます。徹底的なテストは確かに何もブレークを行わないために実行する必要があります。evalを使用しないと、本当に必要ではない場合、 別の実用的なソリューションであるかもしれません。
厳密性に中立なコード
strictコードをstrictモードに移行するポテンシャルの"downside"は、セマンティクスは、strictモードを実装していないレガシーブラウザでは異なる場合があることです。(悪い連結または縮小など)いくつかのまれで、コードもまた、それを書いて、テストモードで実行されない場合があります。ここでは、コードを厳密に中立にするルールがあります。:
- 厳密としてコードを記述し、厳密な専用のエラー(上記の"New runtime errors"セクションから)がスローされないことを確信しています。
- 意味の違いから離れる
eval
: 何をやっているか知っている場合にのみ、それを使用してください。arguments
: 常に名前を経由して関数引数にアクセスしてください。または、使用している引数オブジェクトのコピーを実行してください。:
var args = Array.prototype.slice.call(arguments)
関数の一行目としてthis
: 自ら生成したオブジェクトへ参照するときのみthis
を使用してください。