昔からある変数宣言方法であるvarですが、ECMAScript2015(ES6)から新たにlet, constが導入されてから、開発者の中でもvar宣言は非推奨とされるようになりました。
そもそも、let, constが追加された理由はvarの問題点を改善するため。JavaScriptやECMAScriptについて詳細に説明がされている JavaScript Primer にもvarの問題点とES6でlet, constが追加された経緯が説明されています。
この学習記録では、varがなぜ非推奨か改めて整理しようと思います!
【前提】JavaScriptの変数宣言の種類
まず初めに、変数宣言のパターンとそれぞれの特徴を簡単にまとめます。
宣言方法 | 再宣言 | 再代入 | スコープ | 初期化 |
---|---|---|---|---|
var | ● | ● | 関数 | undefined |
let | X | ● | ブロック | X |
const | X | X | ブロック | X |
それでは早速、varの問題点と非推奨な理由を下記に分けてまとめていきます!
- ホイスティング(変数の巻き上げ)時にundefinedで初期化される
- 関数スコープであることの問題
- 同じ変数名での再宣言が可能
- グローバルスコープの変数を上書きできる
ホイスティング(変数の巻き上げ)時にundefinedで初期化される
下記のようなコードを書いたときに、varとletではエラーの有無に違いが出てきます。
console.log(a);
console.log(b);
var a = 1;
let b = 1;
/* console.log(a)の結果
undefined
*/
/* console.log(b)の結果
Uncaught ReferenceError: Cannot access 'b' before initialization
*/
letの場合はホイスティングの際に、変数宣言文より前に変数を参照すると「初期化前に変数にアクセスしている」というReferenceErrorが出るようになっています。でもvarの場合は、undefined
と表示されるだけでエラーになりません。
開発者は変数aは1を返すと考えて組んでいても、undefinedになっていることに気づかず、意図しない事態になりかねないので問題という訳です。
関数スコープであることの問題
これは書いて見たほうが分かりやすいので、letと比較して一度適当なコードを書いてみます。
function a () {
if (true) {
let b = 1;
var c = 1;
}
console.log(b);
// 結果:Uncaught ReferenceError: b is not defined
console.log(c);
// 結果:1
}
a();
letはブロックスコープなので、参照できる範囲は上記のソースならif文の中に限られます。でも、varは関数スコープなのでfunction a関数の範囲であればどこからでも参照できてしまいます。これがもし、if文と変数cを参照する記述の間に何百行も空いていたら流石に気づきづらく、これまた意図しない事態になる事があるので、非推奨な理由の一つです。
同じ変数名での再宣言が可能
varは下記のように同じ名前での再宣言を許してしまいます。
var a = 1;
var a = 1;
letであれば下記のようなエラーを出してくれます。
let a = 1;
let a = 1;
// 結果:Uncaught SyntaxError: Identifier 'a' has already been declared
既に同じ名前で宣言されていることに気づかず、再宣言して上書きする可能性があって問題ですが、さらにグローバルオブジェクト(ブラウザ上でのwindow)と合わせて考えるとより一層問題となります。下記の見出しで書いていきますね。
グローバルスコープの変数を上書きできる
まず前提として、関数宣言された関数やvar宣言された変数は、グローバルオブジェクト(ブラウザ上ではwindow)に値が格納されます。
var a = 1;
function b () { console.log('hello') }
console.log(window.a);
// 結果:1
window.b();
// 結果:hello
前の問題点で書いた通り、var宣言は再宣言が可能です。なので、下記みたいな事ができてしまいます。
innerWidth = 10;
console.log(window.innerWidth);
// 結果:10
innerWidthは画面の横幅を取得できる元々windowに組み込まれている変数ですが、その変数を再宣言して上書きできてしまいます。当然開発者の知らないwindowプロパティもあるはずで、知らずに独自の変数として宣言して、windowのプロパティと競合してしまう事態になりかねません。このような意図しない結果を生む可能性があるのでvar宣言は問題ありです。