“use strict”の具体的効能

JavaScriptを扱ったことのある方であれば、
"use strict";
という記述を目にしたことがあるかと思います。
読んで字の通り厳格(strict)なモードで書くということを促している、というのはなんとなくわかりますが、では”use strict”を書くのと書かないのではどう違うのだろうと思い、今回調べてみました。
“use strict”の予備知識
動的型付け言語であるJavaScriptはプログラミング言語の中でも良くも悪くもトップレベルで自由度が高く、ある意味やりたい放題出来てしまう言語ではあります。
だからこそ便利でもありますが、例えば複数人でコーディングする場合、自由な書き方が出来てしまうせいで記法に差が生じてしまうこともあります。
そういう事態を避けるため、敢えて制約を設けるのに用いるのが”use strict”です。
strictモードはECMAScript5から導入されたものであり、なのでECMASCript5以降に対応していないブラウザではstrictモードも意図した挙動にならないこともあります。strictモードが適用されないということはより規約が緩くなるということなのでコードは滞りなく動く場合が多いとは思われますが、対応・非対応は確認しておいた方が良さそうです。
(とはいえ非対応なものが少数だとは思いますが…)
自分はスクリプトの最上部に”use strict”と書くやり方しか知らなかったのですが、関数の中で限定的に宣言し用いることも出来るそうです。
ただし、
function sample(){
"use strict";
...
}
のように、関数内の一番最初の記述する必要があります。
スクリプト全体をstrictモードにする際も、関数内を限定的にstrictモードにする際も、適応させるコードの一番上に”use strict”を書かなければなりません。
では、具体的にstrictモードだとどのような差があるのか、一般的によく使いそうな部分にまつわるものを見ていきたいと思います。
変数への代入
先に述べた通り、JavaScriptはかなり自由な言語です。例えば文末にセミコロンを書くのを忘れても、JavaScriptが勝手に「ここにセミコロンが入るだろう」と判断してセミコロンがあるものとして動いてくれたりします。
このように、JavaScriptが勝手に判断してくれるというのは変数の代入時にも起こります。
本来は、変数を宣言する際は変数の前にvarやletやconstなど、適切な変数宣言を置く必要がありますが、例えばsampleという変数に1を代入しようとした場合
sample = 1;
と変数宣言を除外してしまっても勝手にJavaScriptが判断して代入されてしまいます。しかし、
"use strict";
sample = 1;
と記述するとこれはエラーを吐きます。strictモードでは変数宣言の無い変数への代入はエラーとして処理されます。
"use strict";
let sample = 1;
など、きちんと宣言すると何も問題なく動きます。
変数宣言には再代入を許さないconstや、許容するletなど役割が違うものがあり、JavaScript側に勝手に判断されると思わぬ挙動をすることがあるので、あらかじめ変数宣言が欠けている場合はエラーとして表してくれた方が親切であると言えます。
また、strictモードだと変数宣言を行っていてもJavaScriptにおける予約語を変数名として扱うとエラーになります。
(逆にいうと、strictモードでなければ使えてしまいます。場合によっては色々な弊害が考えられます)
プロパティの重複
通常のJavaScriptのオブジェクトリテラルにおいて、同様のプロパティ名を指定した場合、最後に指定した値を適用させます。
どういうことかというと、
var obj = {test : 1, test: 2};
console.log(obj.test);
と、objというオブジェクトにtestというプロパティを重複して指定してみると、これは”2″と表示されます。先ほど述べた通り、最後に宣言されたものが採用されます。
strictモードでは上記のコードはエラーとなります。そもそも重複したプロパティの指定を許しません。
8進法表記
console.log(010 === 8);
というコードをなんらかのJSファイルに記述して実行してみてください。
実はこれは「true」と表示されます。
JavaScriptにおいて、頭が0の数列は8進数として処理されます。なので「010」は10進数の「8」として扱われます。
“===”を用いた厳密な比較においても010と8は等しいという判定になります。
とはいえ直感的では無いですし、これまた予期せぬ結果を導くことがあります。
scrictモードでは、頭が0の数列が確認できた場合、エラーとなります。
ちなみに、parseIntという関数を用いると8進数を安全に10進数に変換することができます。
まとめ
そもそも自分に馴染みのない箇所が多かったので省きましたが、上記以外にもevalやargumentsの使用方法を制限したりだとか、withの使用を禁止したりだとか、strictモードは色々と必要な制限を施してくれます。
strictモードを調査するにあたって、翻ってプレーンなJavaScriptのある種過剰な柔軟さに改めて気付かされました。
自由すぎるのも考えものかもしれません。