JavaScriptの「Strict Mode」とは?
Strict Modeとは何か?
Strict Mode(厳格モード)は、JavaScriptのエラーをより明白にする方法です。コードのパフォーマンスを最適化したり、いくつかのセキュリティの脆弱性を防ぐことができます。
JavaScriptでは、多くの場合、エラーや将来エラーを引き起こす可能性のあることが無視されてしまいます。言語自体が非常に寛容で、構文エラーに悩まされることなく学ぶことができるため、初学者には習得が容易です。しかし、先に進むと問題を引き起こすことがあります。
Strict Modeは、これらのミスを発見したときにエラーを発生させる方法であり、コードのデバッグを容易にし、最初からより良いコードを書く手助けになります。
Strict Modeの呼び出し
Strict Modeを使用するには、"use strict";
や'use strict';
という構文を使います。
Strict Modeは、スクリプト全体や個別の関数に適用できます。スクリプトでは、スクリプトの先頭に"use strict"
を書きます。関数の場合には、関数本体の上部に"use strict"
を置きます。
function example() {
"use strict"
return "これは例の関数です"
}
モジュールと関数は、JavaScriptでは自動的にStrict Modeになります。
動作する仕組み
間違いをエラーに変換する
通常の「非厳格モード」のJavaScriptは、多くの間違いをエラーメッセージにせずに通過させます。これにより、意図した通りに動かなくなったときにデバッグが難しくなることがあります。
Strict Modeが禁止することの1つは、const
、let
、var
キーワードを使わずに変数に値を割り当てることです。通常のJavaScriptでは、これによりグローバルスコープに変数が作成され、動作を続けます。しかし、これは望ましい挙動ではありません。変数を誤ってタイプミスして、新しい変数を偶然作成する危険性があります。
let number = 10;
// スペルミスした変数は新しいグローバル変数を作成する
// 望ましい挙動はnumber変数を更新すること
numbr = 20
console.log(number) // 10
"use strict"
let number = 10;
numbr = 20 // エラーが発生する
console.log(number) // エラーの出力のみ表示される
通常のJavaScriptではエラーにならない別の間違いは、書き込み不可の変数に値を割り当てることです。書き込み不可の変数の一例はNaN
です。NaN = 10;
のような間違いはStrict Modeでのみエラーになります。さらなる例はundefined = "string"
です。
Strict Modeは、プリミティブ値に対してプロパティを設定することも防ぎます。プリミティブ値とは、オブジェクトではなくメソッドを持たないデータです。7種類のプリミティブデータ型があります:
- string
- number
- bigint
- boolean
- undefined
- symbol
- null
プリミティブにプロパティを設定する例は以下のとおりです。
"use strict"
true.string = "こんにちは" // TypeError
"string".update = 10 // TypeError
その他のStrict Modeがエラーに変える間違いには、以下のようなものがあります:
- 削除不可のプロパティを削除しようとする
- 同一の名前をパラメーターとして持つこと(例:
function myFunc(a, a, b) {...}
) - 0をプレフィックスとして持つ数字。その理由はこちらにあります。
JavaScriptにおける変数の使用を最適化する
Strict Modeは、コードの最適化を低下させる可能性のある特定の行為を防ぎます。JavaScriptのコンパイラはしばしば各変数がどこに格納されているかを指定できます。変数名はその定義にマッピングされます。これにより、より最適化されたコードが作成されます。しかしながら、JavaScriptにはこれを不可能にするプロパティが存在します。Strict Modeはこれらを禁止します。
with
Strict Modeはwith
プロパティの使用を禁止します。with
は、その文内でオブジェクトのプロパティをローカル変数として利用できるようにします。
const myObject = {
title: "直感的に分かるダメなデザイン",
author: "Steve Krug"
};
with (myObject) {
console.log(`この本は${author}によって書かれました`)
// この本はSteve Krugによって書かれました
}
with
を使用することは推奨されません。なぜなら、ブロック内の任意の変数がオブジェクトのプロパティに関係するか、あるいは周囲のスコープ内の変数に関係する可能性があるためです。これは実行時まで評価されないので、コードを最適化するのを妨げます。そのため、Strict Modeでwith
を使用しようとするとエラーが発生します。
eval
with
のように、eval
もJavaScriptコードの最適化を困難にします。eval
は文字列を受け取り、それをJavaScriptコードとして評価する関数です。
cont x = 5
eval("x + 5") // 10
eval
が問題なのは(セキュリティの脆弱性を除いて)、それが周囲のスコープに変数を導入する可能性があるためです。つまり、eval
関数内のコードが関数の外の変数を変更したり上書きしたりすることができます。そしてJavaScriptがこれを実行時までチェックできないため、非効率を引き起こす可能性があります。
Strict Modeでは、eval
内で作成された変数はその関数内にのみ存在します。
eval("x = 5")
console.log(x) // 5
"use strict"
eval("x = 5")
console.log(x) // ReferenceError
eval
とarguments
をシンプルにする
JavaScriptでは、eval
とarguments
が予想外の挙動を示すことがあります。Mozillaはこれらについて次のように述べています:
Strict Modeは、
arguments
とeval
をより一般的なキーワードのように扱います。両方とも通常のコードではかなり特殊な挙動を示します:bindingの追加や削除、binding値の変更に関するeval
、index付きプロパティによる名前付き引数のaliasingに関するarguments
です。
Strict Modeを使用することで、eval
とarguments
は他のキーワードのように扱われます。
JavaScriptをより安全にする
JavaScriptはブラウザで操作され、個人情報をアクセスされる可能性があります。JavaScriptはこのような事態を防ぐために、実行される前に部分的にJavaScriptを変換することができます。しかし、コードがうまく書かれていない場合、これには実行時に多くのリソースが必要になります。Strict Modeは、より安全になるようにJavaScriptを書くように強制します。
Strict Modeを使わない状態では、関数からグローバルオブジェクトにアクセスして、セキュリティリスクを提示する方法でJavaScriptを操作することが可能になるかもしれません。これは関数に渡されるthis
値に関係しています。Strict Modeはthis
をオブジェクトに強制的に変換されることを防ぎ、指定されていない場合はundefined
になるため、悪意のある行為者がglobal
またはwindow
オブジェクトにアクセスすることはできません。this
についての詳細はこちらで読むことができます。
関数のもう1つのセキュリティ脆弱性で、Strict Modeが修正しようとしているのはJavaScriptの拡張です。関数が呼ばれたときに.caller
拡張を使用すると、それを呼び出した関数が明らかになり、.arguments
はその引数を示します。これによって「セキュア」な関数を介して保護されていない引数にアクセスできることがあります。Strict Modeのコードで誰かが.caller
または.arguments
にアクセスしようとすると、TypeError
が発生します。
新しいキーワード
Strict Modeでは、いくつかの追加の予約キーワードがあります。これらは将来のJavaScriptのバージョンで使用される可能性が高い単語です。新しいバージョンへの移行を容易にするための措置として導入されています。これらには以下のようなものが含まれます:
implements
interface
package
private
protected
public
static
yield
Strict Modeの詳細と、より技術的な説明については、Mozillaのドキュメントをご覧ください。
こちらの記事はdev.toの良い記事を日本人向けに翻訳しています。
https://dev.to/johnpalmgren/what-is-javascript-strict-mode-5g30