JavaScriptのuse strict(厳格モード)で防げる9個のbadパターン

use strict(厳格モード)とは

JavaScriptのuse strict(厳格モード)を使うと好ましくない記法を制限できます。

JavaScriptは自由度が高いので、例えば「num = 1」のようにletやconstなどを付けなくても問題なく実行されてしまう。

しかし、'use strict' を付けるとConsoleで「Uncaught ReferenceError: num is not defined」というエラーが表示されるため、変数の宣言漏れなどに気づきやすくなります。

'use strict'
num = 1
console.log(num)

最近はTypeScriptやViteなどのビルドツールによりコードを書けば自動的に 'use strict' が追加されることが多い。

そのため、あまり意識することは少なくなったが、現在でもWebサイトによってはJavaScriptファイルに直接書き込んだり、HTMLでインラインで書くケースもあるので、その場合は 'use strict' を必ず入れたほうが良いです。

use strictはグローバルに書かない

'use strict' をグローバルに書くと範囲が広すぎて他の外部スクリプトなども対象になってしまうので、使用する場合は(() => {})()などで囲むなどしてスコープを絞り込んでください。

(() => {
  'use strict'
  num = 1
  console.log(num)
})()

※ 以降はコードを簡略化するためスコープ用の即時関数は省略してます。

use strictで防げる9個のbadパターン

'use strict' を使用することで、どのようなパターンがエラーになるのか知っている人は少ない。

以降にuse strictで防げる9個のbadパターンをまとめました。

1. 宣言なしの変数への代入

「num = 1」のようにletやconstなどを付けないで代入するとエラーになります。

'use strict'
num = 1
console.log(num)
// Uncaught ReferenceError: num is not defined

2. 予約語への代入

「let enum = 1」のように予約語を宣言するとエラーになります。

'use strict'
let enum = 1
console.log(enum)
// Uncaught SyntaxError: Unexpected strict mode reserved word

3. 書き換え不可能なグローバルへの代入

undefinedなどの書き換え不可能なグローバルへの代入はエラーになります。

'use strict'
let undefined = 1
console.log(undefined)
// Uncaught SyntaxError: Identifier 'undefined' has already been declared

4. 書き換え不可能なプロパティへの代入

Object.freezeやObject.definePropertyを使用した書き換え不可能なプロパティへの代入はエラーになります。

'use strict'
let obj = { foo: 1 }
Object.freeze(obj)
obj.foo = 2
console.log(obj.foo)
// Uncaught TypeError: Cannot assign to read only property 'foo' of object '#<Object>'

4. 削除できないプロパティを削除

deleteで削除できないプロパティを削除しようとするとエラーになります。

'use strict'
delete Array.prototype
// Uncaught TypeError: Cannot delete property 'prototype' of function Array() { [native code] }

5. 引数名が重複

(a, a, c)のように引数名が重複しているとエラーなります。

'use strict'
function add(a, a, c) {
  return a + a + c
}
console.log(add(1, 2, 3))
// Uncaught SyntaxError: Duplicate parameter name not allowed in this context

6. プリミティブ値にプロパティを設定

プリミティブ値 (文字列、数値、BigInt、真偽値、undefined、シンボル)にプロパティを設定するとエラーになる。

'use strict'
'foo'.bar = 1
true.false = 2
// Uncaught TypeError: Cannot create property 'bar' on string 'foo'

7. withを使用する

'use strict'
let x = 1
let obj = {}
with (obj) { x }
// Uncaught SyntaxError: Strict mode code may not include a with statement

withを使用するとエラーになる。

8. 0を先頭とした8進数表記

0を先頭とした8進数表記だとエラーになる。

0oを先頭とした8進数表記ならエラーにならない。

'use strict'
let num = 010 // 0o10 はエラーにならない
console.log(num) // 8
// SyntaxError: Octal literals are not allowed in strict mode.

9. 宣言した変数や引数をdelete

宣言した変数や引数にdeleteを使用するとエラーになります。

'use strict'
let foo = 1
delete foo
console.log(foo)
// SyntaxError: Delete of an unqualified identifier in strict mode.

おまけ: 'use strict' は厳格ではない

use strict(厳格モード)という名前だがvarは普通に使えるし、'use strict' が重複してもエラーにならず、関数の再定義などもエラーにならない。

名前からして厳格にチェックされそうな感じはするが、実際はこの記事に書いた9個しかエラーにならないので、過信は禁物です。

'use strict'
function foo() {}
function foo() {
  console.log(1)
}
foo()
// 関数を再定義してもエラーにはならない
// ESLintならno-func-assignでエラーにできる

また、use strictはエラーとして出るのは最初の1箇所だけなので、複数箇所にエラーがあっても、一度にすべてのエラーが表示されないので不便です。

'use strict'
foo = 1
bar = 2
// foo is not defined

そもそもTypeScriptやビルドツールなどを使わず、ESLintも通さずにJavaScriptのコードを書くこと自体がバッドプラクティスなので、もしそのような書き方をしているのなら改善したほうが良いです。

最後に一つ、'use strict' はスペルを間違えると無効になるので、書き慣れていない方は注意が必要です。

// 以下はスペルミスによりすべて無効
'use strect'
'use  strict'
'use strict'