strictモードとは?[JavaScript].NET TIPS

堅牢なJavaScriptコードを書く上でstrictモードはぜひ使いたい機能だが、落とし穴もある。本稿ではstrictモードの使い方と注意点を紹介する。

» 2016年03月16日 05時00分 公開
[山本康彦BluewaterSoft/Microsoft MVP for Windows Development]
.NET TIPS
Insider.NET

 

「.NET TIPS」のインデックス

連載目次

 JavaScriptを書いているとき、うっかり未定義の変数を使ってしまったり、変数名のスペルミスをしてしまって、バグを出してしまったことはないだろうか? そんなことを防いでくれるのがstrictモード(厳格モード)だ。本稿では、その使い方と、二つの注意事項を解説する。

strictモードの宣言と効果

 「"use strict";」(または「'use strict';」)という1文を置くことで、strictモードになる。

 スクリプトの先頭で宣言すれば、スクリプト全体がstrictモードになる。関数の先頭で宣言すれば、その関数内だけがstrictモードになる。それ以外の場所で宣言しても効果はないので注意しよう。

 関数スコープでstrictモードを使う例を、次のコードに示す。

// strictモードを使わない例
(function () {
  x = 10; // ローカル変数のつもりで書いた変数(先頭のvarを書き忘れ)
  var w = 15; // このwは正しくローカル変数
  test(); // x=20, w=15
}());

// 上の関数内のxはグローバルスコープになるので、どこからでも変更できる
function test() {
  x = 20;
  w = 25; // このwは、グローバルスコープの新しい変数になる
}

// strictモードを使う例
(function () {
  "use strict";

  // 未定義変数はエラーになる
  try {
    y = 20;
  }
  catch (e) {
    alert(e);
    // Edgeでのエラーメッセージ
    // ReferenceError: Variable undefined in strict mode
  }
}());

strictモードの例(JavaScript)
関数の先頭に「"use strict";」と書くことで、その関数内がstrictモードになる。関数の途中に書いても有効にならないので注意しよう。
非strictモードでは、変数宣言をしないまま変数を使うと、グローバルスコープで変数が宣言されたものと見なされる。そのため、この例の変数「x」のように、関数内だけで使っているつもりでもグローバルスコープになってしまう。strictモードでは、先頭にvarキーワードを付けて変数を宣言しないとエラーになるので、そのようなミスはなくなる。
なお、この「(function () {……省略……}());」という関数の書き方は即時関数(IIFE、Immediately-invoked function expression)というものだ。無名関数をその場で実行してくれるのである。

 strictモードでは上の例のようにvarキーワードの付け忘れを防いでくれる。その他に、変更できないプロパティへの代入や、関数の引数名の重複(例えば、2つの引数を取る関数で、両方の仮引数名を同じ名前で宣言すること)などがチェックされる。詳細は、MSDNMDNのドキュメントをご覧いただきたい。

 このようなメリットのあるstrictモードは、今どきのJavaScriptでは使うのが当たり前だといえるだろう。ただし、使用に当たって気を付けることが2点あるので、以降で説明する。

スクリプト連結の罠

 上の例では関数内でstrictモードを宣言した。いちいち関数ごとに宣言しなくても、スクリプトの先頭で宣言すればよさそうなものだが、それには落とし穴がある。

 つまり、複数のスクリプトファイルを連結するときに問題になるのだ。全体がstrictモードになっているスクリプトファイルの後ろに、全体が非strictモードになっているスクリプトファイルを連結すると、連結結果は全体がstrictモードになってしまうため、非strictモードのスクリプトの部分でエラーが出てしまう(逆に全体が非strictモードのスクリプトファイルにstrictモードのスクリプトファイルを連結すると、全てが非strictモードになってしまう場合もある)。そのような事態を避けるため、strictモードは関数ごとに宣言する方がよいだろう。

 なお、関数を入れ子にしている場合、外側の関数でstrictモードを宣言すれば内側の関数でも有効だ。

非対応ブラウザで挙動が変わる罠

 全てのブラウザでstrictモードがサポートされているわけではない。最近のデスクトップPC用ブラウザなら対応しているが、例えばIE9以下やAndroid 4.0以下など、ちょっと古いブラウザの中には対応していないものもある。

 非対応ブラウザでも、strictモードの宣言はただの文字列リテラルなので、エラーになることはない。しかし、挙動が変わる場合があるので、strictモード非対応ブラウザでのテストは欠かせない。

 例としてeval関数で挙動が変わる例を次のコードに示す。

// strictモード
(function () {
  "use strict";
  var z = 30;
  // strictモードでは、上のzと下のeval内のzは別物
  var result = eval("var z = 45; z;");
  // z=30, result=45
}());

// 非strictモード
(function () {
  var z = 30;
  // 非strictモードでは、上のzと下のeval内のzは同じ物
  var result = eval("var z = 45; z;");
  // z=45, result=45
}());

モードによって挙動が変わってしまう例(JavaScript)
strictモードでは、ローカル変数zと、eval関数内で宣言している変数zとは別物になるので、eval関数実行後もローカル変数zは30のままだ。ところが、これをstrictモード非対応のブラウザで実行すると、下側のようにeval関数内での代入がローカル変数zに対して行われてしまうため、eval関数実行後のローカル変数zは45に変わってしまう。
このようなモードによって挙動が変わってしまうコードは、(ブラウザが限定できない場合には)書かないようにするしかない。

【コラム】VBのOption Strict

 VBの開発者はOption Strictステートメントを連想するかもしれないが、むしろ「"using strict";」はOption Explicitステートメントに近い。


まとめ

 つまらないミスを防止するため、関数の先頭には「"use strict";」を書いてstrictモードにしよう。関数を入れ子にする場合は、一番外側の関数だけに書けばよい。

 ただし、strictモード非対応ブラウザでは挙動が変わる場合があるので、非対応ブラウザでのテストも必要だ。

「.NET TIPS」のインデックス

.NET TIPS

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。