技術とか戦略とか

IT技術者が技術や戦略について書くブログです。

JavaScript:Strictモードとは

JavaScriptには「Strictモード」と呼ばれるモードが用意されています。
Strictモードにすることで、バグに気付かずに実行が継続されるのを防ぎやすくなり、高速化することもあります。
 
詳しくはMozillaのページ(https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Strict_mode)に書かれていますが、この記事では簡単に紹介したいと思います。
 
----
 
Strictモードに設定するためには、以下の2つの方法があります。
(export句を使用した方法もありますが、この記事では割愛します)
 
1.スクリプト全体で定義
スクリプトの最初に「'use strict';」を記述することで、そのスクリプト全体がStrictモードになります。
 
・サンプルコード
'use strict'; // スクリプトの最初で定義、スクリプト全体がstrictモード
console.log("Hello world!");
 
2.関数全体で定義
関数の最初に「'use strict';」を記述することで、その関数全体がStrictモードになります。
 
・サンプルコード
function hoge() {
 'use strict'; // 関数の最初で定義、関数全体がstrictモード
 console.log("Hello world!");
}
// 関数の外はstrictモードではない
hoge();
 
----
 
Strictモードに設定することで、例えば以下のような挙動変更が行われます。
 
1.バグになりやすい誤りがある場合に異常終了させる
例えば、定義済みの変数を参照しようとして変数名の記述を誤った場合、Strictモードの場合は異常終了させることができます。
 
・サンプルコード(非Strictモード)
// 'use strict';
let hoge = "definition";
hage = "Hello world!";
console.log(hoge);
 
・実行結果(非Strictモード)
C:\tmp>node hello.js
definition

C:\tmp>
 
・サンプルコード(Strictモード)
'use strict';
let hoge = "definition";
hage = "Hello world!";
console.log(hoge);
 
・実行結果(Strictモード)
C:\tmp>node hello.js
C:\tmp\hello.js:3
hage = "Hello world!";
   ^

ReferenceError: hage is not defined
  at Object.<anonymous> (C:\tmp\hello.js:3:6)
  at Module._compile (internal/modules/cjs/loader.js:1137:30)
  at Object.Module._extensions..js (internal/modules/cjs/loader.js:1157:10)
  at Module.load (internal/modules/cjs/loader.js:985:32)
  at Function.Module._load (internal/modules/cjs/loader.js:878:14)
  at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
  at internal/main/run_main_module.js:17:47

C:\tmp>
 
2.セキュリティーの強化
JavaScriptでは、必ずオブジェクトを用意する必要があり、自分でオブジェクトを定義しない場合は「グローバルオブジェクト」と呼ばれるブラウザや実行環境が用意したオブジェクトが使用されます。
また、キーワード「this」を使用することで、記述箇所を動かしているオブジェクトの情報を取得することができます。
「this」によりグローバルオブジェクトを参照された場合、セキュリティー上の問題が発生する可能性があるため、Strictモードではグローバルオブジェクトが参照されるようなケースで「this」キーワードは「undefined」を返すようになります。
 
・サンプルコード(非Strictモード)
//'use strict';
function hoge() {
 console.log(this); // 関数を呼び出しているオブジェクトを参照
}
hoge(); // グローバルオブジェクトの関数を実行
let hello = {}; // 独自のオブジェクト定義
hello.hoge = hoge; // 独自のオブジェクトに関数を定義
hello.hoge(); // 独自のオブジェクトの関数を実行
 
・実行結果(非Strictモード)
C:\tmp>node hello.js
Object [global] {
 global: [Circular],
 clearInterval: [Function: clearInterval],
 clearTimeout: [Function: clearTimeout],
 setInterval: [Function: setInterval],
 setTimeout: [Function: setTimeout] {
  [Symbol(nodejs.util.promisify.custom)]: [Function]
 },
 queueMicrotask: [Function: queueMicrotask],
 clearImmediate: [Function: clearImmediate],
 setImmediate: [Function: setImmediate] {
  [Symbol(nodejs.util.promisify.custom)]: [Function]
 }
}
{ hoge: [Function: hoge] }

C:\tmp>
 
・サンプルコード(Strictモード)
'use strict';
function hoge() {
 console.log(this); // 関数を呼び出しているオブジェクトを参照
}
hoge(); // グローバルオブジェクトの関数を実行
let hello = {}; // 独自のオブジェクト定義
hello.hoge = hoge; // 独自のオブジェクトに関数を定義
hello.hoge(); // 独自のオブジェクトの関数を実行
 
・実行結果(Strictモード)
C:\tmp>node hello.js
undefined
{ hoge: [Function: hoge] }

C:\tmp>
 
3.将来(最新)のJavaScriptの仕様に対応する
例えば、キーワード「private」は、2021/02/21現在でいくつかのブラウザやNode.jsでは使用可能です。
非Strictモードではこのキーワードを変数名として使用できますが、Strictモードではエラーにできます。
 
・サンプルコード(非Strictモード)
// 'use strict';
let private = "Hello world!";
console.log(private);
 
・実行結果(非Strictモード)
C:\tmp>node hello.js
Hello world!

C:\tmp>
 
・サンプルコード(Strictモード)
'use strict';
let private = "Hello world!";
console.log(private);
 
・実行結果(Strictモード)
C:\tmp>node hello.js
C:\tmp\hello.js:2
let private = "Hello world!";
^^^

SyntaxError: Unexpected strict mode reserved word
  at wrapSafe (internal/modules/cjs/loader.js:1053:16)
  at Module._compile (internal/modules/cjs/loader.js:1101:27)
  at Object.Module._extensions..js (internal/modules/cjs/loader.js:1157:10)
  at Module.load (internal/modules/cjs/loader.js:985:32)
  at Function.Module._load (internal/modules/cjs/loader.js:878:14)
  at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
  at internal/main/run_main_module.js:17:47

C:\tmp>