はじめに
JavaScriptには、var
,let
,const
という3種類の変数宣言方法があります。これらは、それぞれ異なる特性と用途を持っています。以下に、それぞれの違いを説明します。
var
スコープ
var
で宣言された変数は、関数スコープを持ちます。これは、変数が宣言された関数の中で有効であることを意味します。もし関数外でvar
を使用すると、その変数はグローバルスコープとなります。
再宣言
同じスコープ内で同じ名前の変数を再宣言することができます。
ホイスティング
var
で宣言された変数は、ホイスティングと呼ばれるJavaScriptの動作により、実際に宣言される前に使用可能です。ただし、宣言より前に使用すると値はundefined
になります。
console.log(x); // undefined
var x = 5;
console.log(x); // 5
let
スコープ
let
で宣言された変数は、ブロックスコープを持ちます。これは、変数が宣言されたブロック内(中括弧{}
で囲まれた部分)でのみ有効であることを意味します。
再宣言
同じスコープ内で同じ名前の変数を再宣言することはできません。
ホイスティング
let
もホイスティングされますが、宣言より前にアクセスしようとするとReferenceError
が発生します。これは「一時的死区間 (Temporal Dead Zone)」と呼ばれる現象です。
{
let y = 10;
console.log(y); // 10
}
// console.log(y); // ReferenceError: y is not defined
const
スコープ
const
もlet
と同様に、ブロックスコープを持ちます。
再宣言・再代入
const
で宣言された変数は、再宣言も再代入もできません。ただし、オブジェクトや配列のプロパティを変更することは可能です。
ホイスティング
const
もホイスティングされますが、let
と同様に「一時的死区間 (Temporal Dead Zone)」が存在します。
const z = 20;
console.log(z); // 20
// z = 30; // TypeError: Assignment to constant variable.
// オブジェクトの例
const person = { name: "Alice" };
person.name = "Bob"; // OK
console.log(person.name); // "Bob"
// person = { name: "Charlie" }; // TypeError: Assignment to constant variable.
ホイスト(ホイスティング)
ホイスト(ホイスティング)とは、JavaScriptの動作において、関数宣言や変数宣言が実際にコードが実行される前にそのスコープの一番上に移動されることを指します。
つまり、関数宣言や変数宣言がコード内のどの位置に書かれていても、その宣言がスコープ内で最初に処理されるため、コード内のどの場所でもそれらを呼び出すことができるという特徴があります。
console.log(myFunction()); // "Hello, World!" を出力
function myFunction() {
return "Hello, World!";
}
このコードはエラーを出さずに "Hello, World!" を出力します。これは、関数myFunction
の宣言が実際のコードの実行前にホイストされているためです。
ただし、変数宣言に関しては、var
を使った宣言はホイストされますが、その値の代入はホイストされません。let
やconst
を使った変数宣言の場合、ホイストはされますが、宣言と初期化が結びついており、宣言される前にアクセスしようとするとReferenceError
が発生します。
console.log(myVar); // undefined
var myVar = 10;
console.log(myVar); // 10
console.log(myLet); // ReferenceError: myLet is not defined
let myLet = 20;
console.log(myLet); // 20 (ここまで実行されない)
この例では、var
を使った変数宣言がホイストされるため、最初のconsole.log(myVar)
でundefined
が出力されますが、let
の場合はホイストされますが初期化される前にアクセスしようとするとエラーが発生します。
これは、let
とconst
が「一時的死区間 (Temporal Dead Zone)」という概念を持っているためです。
つまり、ホイストとは、JavaScriptエンジンがコードを解釈する際に、関数宣言と変数宣言をスコープの先頭に移動させる動作を意味しています。
これにより、宣言された場所に関係なく、スコープ内でそれらを使用することができますが、let
とconst
に関しては特定の注意が必要です。
一時的死区間 (Temporal Dead Zone)
「一時的死区間 (Temporal Dead Zone, TDZ)」は、let
やconst
で宣言された変数がスコープ内で宣言される前にアクセスできない期間を指します。
TDZは、変数が宣言されたときから初期化されるまでの間のことを指し、この期間内に変数にアクセスしようとすると、ReferenceError
が発生します。
一時的死区間の概念
TDZの範囲
let
やconst
で宣言された変数は、そのスコープ(関数やブロック)内で、宣言される前にアクセスすることができません。TDZは、変数の宣言が行われる位置から、変数が初期化される位置までの間に存在します。
TDZの目的
TDZは、変数の宣言と初期化が分離されているため、意図しない動作やバグを防ぐための仕組みです。これにより、変数の使用がより予測可能で安全になります。
TDZの動作例
TDZがどのように機能するかを示します。
function example() {
console.log(a); // ReferenceError: Cannot access 'a' before initialization
let a = 5;
console.log(a); // 5
}
example();
このコードでは、let
で宣言された変数a
に対して、初期化される前にアクセスしようとすると、ReferenceError
が発生します。これがTDZです。
TDZが発生する状況
TDZは以下のような状況で発生します。
ブロックスコープ内での変数宣言:
{
console.log(x); // ReferenceError: Cannot access 'x' before initialization
let x = 10;
}
関数内での変数宣言
function foo() {
console.log(y); // ReferenceError: Cannot access 'y' before initialization
const y = 20;
}
foo();
TDZの理解と扱い
初期化前の変数アクセス
TDZは、変数が宣言される前にアクセスすることで発生します。これは、変数がスコープに入ってからも、初期化されるまでの間は有効です。
TDZを避ける
TDZを避けるためには、変数を使用する前に必ず宣言し、初期化を行うことが重要です。これにより、意図しないエラーを防ぐことができます。
まとめ
var
,let
,const
にはそれぞれ異なる特性があり、用途に応じて使い分けることが大切です。通常は、必要な変数を変更しないようにするためにconst
を使用し、必要な場合にのみlet
を使用するのが一般的です。