現在はJavaScriptで変数を宣言するときにlet
を使用するのが主流ですが、ES6よりも前のバージョンではvar
を使用していました。
私がこの業界に入った時点で既にES6になっており、let
を使用することを推奨されたため、var
を使用したことがありません。
今回、改めて違いを知りたいなと思いそれぞれの違いをまとめてみました。
➀スコープ
let
とvar
では、変数の参照できる範囲「スコープ」が異なります。
let
を使用する場合、if文の中で変数を設定すると「ブロックスコープ」になります。
そのため、下記の例のようにif文の外で変数を参照するとエラーが発生します。
if(true) {
let x = 2;
console.log(x); // 2
}
console.log(x); // Uncaught ReferenceError: x is not defined
一方、var
を使用して変数宣言を行った場合、どれだけ深い入れ子になっていても変数のスコープは関数全体になります。
if(true) {
var x = 2;
console.log(x); // 2
}
console.log(x); // 2
➁グローバル変数
let
もvar
も関数の外側で変数を宣言した場合、この変数はグローバル変数になります。
しかしこれらは重要な点が異なります。
var
を使って宣言したものは、グローバルオブジェクトのプロパティとして実装されます。
グローバルオブジェクトとは
グローバルオブジェクトは、グローバルスコープ上に常時存在するオブジェクトです。
JavaScript では、グローバルオブジェクトが常に定義されています。ウェブブラウザー上でスクリプトがグローバル変数を生成する時、グローバルオブジェクトのメンバーとして作成されます。
つまり、グローバルオブジェクトの関数や変数はどこからでも参照することができるのです。
グローバルオブジェクトはglobalThis
で参照できるので、関数の外側でvar x = 2;
と記述した場合、globalThis.x = 2;
と記述したのと同じになります。
なお、let
を使って宣言したグローバル変数は、グローバルオブジェクトのプロパティになりません。
var x = 2;
console.log(globalThis.x); // 2
let y = 2;
console.log(globalThis.y); // undefined
ただし、まったく同じグローバル変数というわけではありません。var
を使って宣言したプロパティはdelete
演算子をつかって削除できません。
// 通常のグローバル変数
globalThis.globalVar = "hello world";
console.log(globalThis.globalVar); // hello world
delete globalThis.globalVar;
console.log(globalThis.globalVar); // undefined
// varで宣言
var myVar = "hello world";
console.log(globalThis.myVar); // hello world
delete globalThis.myVar;
console.log(globalThis.myVar); // hello world
➂再宣言
一度宣言した変数を、同じ変数名で宣言することを再宣言と言います。
let
を使用する場合は再宣言するとエラーが発生しますが、
var
の場合は後に宣言した変数が適用されます。
// let
let x = 2;
let x = 10;
console.log(x); // SyntaxError: Identifier 'x' has already been declared
// var
var y = 2;
var y = 10;
console.log(x); // 10
➃ホイスティング(巻き上げ)
そもそもホイスティングとは?
avaScript の巻き上げ (Hoisting) は、インタープリターがコードの実行前に、関数、変数、クラス、インポートの宣言をそのスコープの先頭に移動するように見えるプロセスを指します。
言葉だけでは分かりづらいので実際に例を見てみましょう。
下記はlet
の例です。
console.log(x); // Cannot access 'x' before initialization
let x = 2;
console.log(x); // 2
let
の宣言前に参照しようとするとエラーが発生します。
では、var
の場合はどうでしょう。
console.log(x); // undefined
var x = 2;
console.log(x); // 2
エラーではなく、undefined
が出力されています。
var
の場合、宣言されるとコード実行前にメモリが確保されます。
あくまでメモリの確保の実で、値は代入されていないのでundefined
となっています。
おわりに
使い方は同じとは言え、var
は予期せぬエラーを誘導する可能性を孕んでいます。
意図しない動作を防ぐためにも、基本的にはlet
やconst
を使用する方がよさそうです。
それでは。