【JavaScript】3種類の変数宣言

はじめに

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

スコープ

constletと同様に、ブロックスコープを持ちます。

再宣言・再代入

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を使った宣言はホイストされますが、その値の代入はホイストされません。letconstを使った変数宣言の場合、ホイストはされますが、宣言と初期化が結びついており、宣言される前にアクセスしようとすると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の場合はホイストされますが初期化される前にアクセスしようとするとエラーが発生します。

これは、letconstが「一時的死区間 (Temporal Dead Zone)」という概念を持っているためです。

つまり、ホイストとは、JavaScriptエンジンがコードを解釈する際に、関数宣言と変数宣言をスコープの先頭に移動させる動作を意味しています。

これにより、宣言された場所に関係なく、スコープ内でそれらを使用することができますが、letconstに関しては特定の注意が必要です。

一時的死区間 (Temporal Dead Zone)

「一時的死区間 (Temporal Dead Zone, TDZ)」は、letconstで宣言された変数がスコープ内で宣言される前にアクセスできない期間を指します。

TDZは、変数が宣言されたときから初期化されるまでの間のことを指し、この期間内に変数にアクセスしようとすると、ReferenceErrorが発生します。

一時的死区間の概念

TDZの範囲

letconstで宣言された変数は、そのスコープ(関数やブロック)内で、宣言される前にアクセスすることができません。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を使用するのが一般的です。

関連記事

【JavaScript】スプレッド構文
# はじめに スプレッド構文は、JavaScriptでデータを展開する際に非常に便利な機能です。JavaScriptにおけるスプレッド構文の基本的な使い方とその応用について説明します。 # スプレッド構文の基本 スプレッド構文は、配列やオ [...]
2024年8月7日 10:57
【JavaScript】||(論理和演算子)と??(Nullish Coalescing演算子)の違い
# はじめに JavaScriptでの`||`(論理和演算子)と`??`(Nullish Coalescing演算子)は、どちらも値を選択する際に使われる演算子ですが、それぞれの動作には重要な違いがあります。 # ||(論理和演算子) ` [...]
2024年8月1日 10:58
【JavaScript】4種類の関数とそれぞれの特性・使い所
# はじめに JavaScriptの関数は、コードの再利用やモジュール化を実現するための基本的な要素です。関数は、プログラムの複雑さを管理しやすくし、コードの可読性と保守性を向上させます。 JavaScriptには、いくつかの異なる方法で関 [...]
2024年7月30日 12:19
【JavaScript】「名前付きエクスポート/インポート」と「デフォルトエクスポート/インポート」
# はじめに JavaScriptのエクスポートは、モジュールを使用してコードを分割し、再利用可能にするための重要な概念です。エクスポートを利用することで、他のファイルから関数や変数、クラスをインポートして使用することができます。 Java [...]
2024年7月30日 11:46
【CSS+JS】メニューアイコンの一種、ベントーメニューの実装方法(アニメーション付き)
# はじめに メニューアイコンの中ではハンバーガーメニューが有名だと思いますが、その他にもいろいろな種類があって、それぞれに名前もつけられています。 <a class="gallery" data-group="gallery" href= [...]
2021年10月18日 14:26
【CSS+JS】メインコンテンツの裏から現れるフッターの実装方法
# はじめに オシャレなサイトなどでたまに見かける「メインコンテンツの裏から現れるフッター」の実装方法について説明します。 # サンプル <iframe height="392" style="width: 100%;" scrollin [...]
2021年10月18日 13:26
【CSS+JS】背景画像の視差効果(パララックス)を実装する方法
# はじめに JavaScriptプラグインを使わずに、背景画像の視差効果(パララックス)をVanilla JS(ピュアなJavaScript)だけで実装する方法について説明します。 # サンプル まず、背景画像の視差効果(パララックス) [...]
2021年10月17日 12:08
【CSS+JS】現在のスクロール量を確実に取得する(プロパティ対応状況まとめ)
# はじめに JavaScriptで現在のスクロール量を取得するためのプロパティはたくさんあります。種類がありすぎるため、かえってどれを使えばいいのかいまいちわからないという人も多いかと思います。 本記事では、各プロパティのブラウザ対応状況 [...]
2021年6月5日 15:51