JavaScriptを学習する上で、変数の宣言方法である`var`と`let`の違いは、初学者にとって混乱しやすいポイントの一つです。しかし、この二つの違いを理解することは、より安全で効率的なコードを書くために非常に重要です。本記事では、この「varとletの違い」を、分かりやすく、そして実践的に解説していきます。
スコープの違い:どこまで変数が見える?
`var`と`let`の最も大きな違いは、変数の「スコープ」、つまり変数がどこからアクセスできるかという範囲にあります。`var`で宣言された変数は、関数スコープまたはグローバルスコープを持ちます。これは、関数の中であればどこからでもアクセスでき、関数外で宣言した場合はプログラム全体でアクセスできるようになるということです。
一方、`let`で宣言された変数は、ブロックスコープを持ちます。ブロックスコープとは、`{}`(波括弧)で囲まれた範囲のことです。例えば、`if`文や`for`ループの中などで`let`を使って変数を宣言した場合、その変数はその波括弧の中だけで有効になり、外からはアクセスできなくなります。これは、意図しない変数の上書きや、コードの可読性を低下させることを防ぐ上で、 非常に重要なメリット となります。
このスコープの違いを具体的に見てみましょう。
- varの場合:
- letの場合:
関数スコープ
ブロックスコープ
例えば、以下のようなコードを想像してみてください。
if (true) {
var x = 10;
}
console.log(x); // 10 と出力される
if (true) {
let y = 20;
}
console.log(y); // エラーになる (ReferenceError: y is not defined)
このように、`var`は`if`文の外でも`x`にアクセスできますが、`let`は`if`文の外では`y`にアクセスできません。この違いは、コードのバグを防ぐ上で`let`が優れていることを示しています。
巻き上げ(ホイスティング)の違い:宣言前のアクセス
`var`と`let`のもう一つの重要な違いは、「巻き上げ(ホイスティング)」という現象です。巻き上げとは、JavaScriptエンジンがコードを実行する前に、変数の宣言をスコープの先頭に「巻き上げる」ように処理する仕組みのことです。
`var`で宣言された変数は、巻き上げによって宣言と初期化(undefinedという値が自動的に代入されること)が行われます。このため、宣言よりも前にその変数にアクセスしても、エラーにはならずに`undefined`という値が返ってきます。これは、一見便利に思えるかもしれませんが、意図しない挙動を引き起こす原因となることもあります。
一方、`let`で宣言された変数は、巻き上げの仕組みはありますが、宣言されるまで(コード上で`let`と書かれるまで)はアクセスできません。宣言される前にアクセスしようとすると、ReferenceErrorが発生します。この挙動は、コードの意図しないバグを防ぎ、より安全に変数を使用できることを意味します。
巻き上げについて、具体的に比較してみましょう。
| var | let | |
|---|---|---|
| 巻き上げ | 宣言と初期化(undefined)が行われる | 宣言は行われるが、初期化はされない(TDZ: Temporal Dead Zone) |
| 宣言前のアクセス | undefinedが返る | ReferenceErrorが発生する |
以下のようなコードで違いを確認できます。
console.log(varVariable); // undefined と出力される
var varVariable = "Hello";
console.log(letVariable); // ReferenceError: Cannot access 'letVariable' before initialization となる
let letVariable = "World";
この巻き上げの挙動の違いは、コードを書く際に変数を宣言するタイミングや、安全なコーディングのために`let`を選択する理由を理解する上で役立ちます。
再宣言と再代入の違い:同じ変数名を使える?
`var`と`let`では、同じスコープ内で同じ名前の変数に対して、再宣言や再代入ができるかどうかに違いがあります。
`var`で宣言された変数は、同じスコープ内であれば何度でも再宣言が可能です。これは、意図せずに変数が上書きされてしまうリスクを高めます。また、再代入ももちろん可能です。
一方、`let`で宣言された変数は、同じスコープ内では一度しか宣言できません。しかし、再代入は可能です。これは、意図しない変数の上書きを防ぎ、コードの安全性を高めるための仕様です。
それぞれの挙動を整理してみましょう。
- varの場合:
- 再宣言:可能
- 再代入:可能
- letの場合:
- 再宣言:不可能(エラーになる)
- 再代入:可能
以下のようなコードで違いを確認できます。
var name = "Alice";
var name = "Bob"; // 再宣言は可能
console.log(name); // Bob と出力される
let age = 25;
// let age = 30; // SyntaxError: Identifier 'age' has already been declared となる
age = 30; // 再代入は可能
console.log(age); // 30 と出力される
この「再宣言できない」という`let`の仕様は、コードの堅牢性を高める上で非常に役立ちます。
グローバル変数とwindowオブジェクトの関係
`var`と`let`のスコープの違いは、グローバル変数との関係にも影響を与えます。特に、ブラウザ環境でのJavaScript開発において、この点は重要になります。
`var`でグローバルスコープに宣言された変数は、グローバルオブジェクトである`window`オブジェクトのプロパティとして登録されます。これは、`window.変数名`のようにアクセスできることを意味します。しかし、この挙動は、他のスクリプトやライブラリとの間で意図しない名前の衝突を引き起こす原因となることがあります。
一方、`let`でグローバルスコープに宣言された変数は、`window`オブジェクトのプロパティとして登録されません。これは、`window`オブジェクトを汚染することなく、よりクリーンにグローバル変数を扱えることを意味します。モジュール化されたJavaScript開発においては、この違いがコードの管理を容易にします。
この関係性を表でまとめます。
| グローバル変数として登録されるか | |
|---|---|
| var | はい(windowオブジェクトのプロパティになる) |
| let | いいえ |
例えば、ブラウザの開発者ツールで以下のコードを実行すると違いが分かります。
var globalVar = "I am global var";
let globalLet = "I am global let";
console.log(window.globalVar); // "I am global var" と出力される
console.log(window.globalLet); // undefined と出力される
このように、`let`はグローバルスコープにおいても、より予測可能で安全な変数管理を可能にします。
constとの比較:不変な値の宣言
`var`と`let`の違いを理解した上で、JavaScriptで変数を宣言するもう一つのキーワードである`const`についても触れておきましょう。`const`は「定数」を宣言するためのキーワードです。
`const`で宣言された変数は、一度値が代入されると、その値を変更(再代入)することができません。これは、プログラムの実行中に値が変わっては困るような、固定された値を扱う場合に非常に役立ちます。`const`も`let`と同様にブロックスコープを持ち、巻き上げの挙動も似ています。
`var`、`let`、`const`の主な違いを比較してみましょう。
- var:
- 関数スコープ
- 巻き上げあり(宣言と初期化)
- 再宣言・再代入可能
- グローバル変数は`window`オブジェクトのプロパティになる
- let:
- ブロックスコープ
- 巻き上げあり(宣言のみ、TDZあり)
- 再宣言不可能、再代入可能
- グローバル変数は`window`オブジェクトのプロパティにならない
- const:
- ブロックスコープ
- 巻き上げあり(宣言のみ、TDZあり)
- 再宣言・再代入不可能(一度代入したら変更できない)
- グローバル変数は`window`オブジェクトのプロパティにならない
具体例を見てみましょう。
const PI = 3.14159;
// PI = 3.14; // TypeError: Assignment to constant variable. となる
このように、`const`は値の変更を防ぐことで、コードの意図を明確にし、バグを防ぐのに役立ちます。
一般的には、変数の値が変更されないことが確実であれば`const`を使い、値が変更される可能性がある場合は`let`を使うことが推奨されています。そして、特別な理由がない限り、`var`の使用は避けるべきです。
まとめ:現代のJavaScript開発ではletとconstが主流
これまで見てきたように、`var`と`let`、そして`const`にはそれぞれ異なる特徴があります。特に、スコープや巻き上げ、再宣言に関する違いは、コードの安全性や保守性に大きく影響します。
現代のJavaScript開発では、`var`の持つ挙動の曖昧さや意図しないバグの原因になりやすい点を考慮し、ほとんどの場合`let`や`const`が使用されています。`let`は値が変更される可能性のある変数に、`const`は値が変更されない定数に使うことで、よりクリーンで、バグの少ないコードを書くことができます。この「varとletの違い」をしっかりと理解し、`let`と`const`を使いこなすことが、JavaScriptエンジニアとしてのスキルアップにつながるでしょう。