はじめに
JavaScriptのコードを読んでいて、
「var、let、constってどうちがうんだっけ?」
「関数が定義される前に使われているのに、なぜか動く……?」
と感じたことはありませんか?
この記事では、これらの宣言子の違いと、JavaScript特有の「巻き上げ(hoisting)」という仕組みを整理して理解します。
これを押さえることで、変数宣言まわりのミスを減らし、コードの挙動をしっかり納得できるようになります。
この記事の内容
- 
var/let/constの違い
- 「巻き上げ(hoisting)」とは何か
- 各宣言子での具体的な動作の違い
- 各宣言子の使い分けの目安
- 実務で let/constが推奨される理由
var, let, const とは
var、let、constは、JavaScriptで変数を宣言するためのキーワードです。
JavaScriptの仕様はECMAScriptという標準仕様で定められており、ECMAScript 5(2009年)まではvarしか存在しませんでした。
letとconstはECMAScript 6(2015年)で導入され、より安全で直感的な変数管理が可能になりました。
各キーワードの違い早見表
| キーワード | 再宣言 | 再代入 | 巻き上げ | 
|---|---|---|---|
| var | ◯ | ◯ | ◯ | 
| let | × | ◯ | × | 
| const | × | × | × | 
この表からわかるように、varは柔軟(=危険)で、letとconstは意図しない再宣言や再代入を防ぐ仕組みになっています。
巻き上げ(Hoisting)とは?
巻き上げ(hoisting)とは、変数や関数の宣言がスコープの先頭に移動したかのように扱われる仕組みのことです。
つまり、プログラムの途中で宣言しても、実際には最初に宣言されたように振る舞うということです。
var による巻き上げの例
console.log(x);
var x = 1;
console.log(x);
一見すると、最初のconsole.log(x)は未定義の変数を参照しているのでエラーになりそうですが、実際には次のように動作します。
var x;             // 巻き上げにより先頭で宣言された扱い
console.log(x);    // undefined
x = 1;
console.log(x);    // 1
var宣言の場合、変数の宣言部分のみが巻き上げられ、初期化はそのままの位置で行われます。
let / const の場合
console.log(y); // ReferenceError
let y = 10;
console.log(z); // ReferenceError
const z = 100;
letやconstも内部的にはスコープの先頭で「予約」されますが、初期化されるまではアクセスできません。この期間を Temporal Dead Zone(TDZ) と呼びます。
関数の巻き上げ
関数宣言も巻き上げの対象になります。そのため、定義より前で呼び出しても動作します。
console.log(square(3)); // OK
function square(x) { return x * x; }
ただし、関数式(変数に関数を代入する形)では挙動が異なります。
console.log(square(3)); // TypeError
var square = function(x) { return x*x; };
ここではvarの巻き上げが起きていますが、代入は後なので、squareは呼び出し時点ではundefinedになっています。
再宣言と再代入
再宣言の違い
var x = 1;
var x = 2; // OK
let y = 10;
let y; // SyntaxError: Identifier 'y' has already been declared
const z = 100;
const z; // SyntaxError: Identifier 'z' has already been declared
letとconstでは同一スコープ内での再宣言は禁止です。
constの初期化
const a; // SyntaxError: Missing initializer in const declaration
constでは宣言と同時に初期化を行う必要があります。
再代入の違い
var x = 1;
x = 2; // OK
let y = 10;
y = 20; // OK
const z = 100;
z = 200; // TypeError: Assignment to constant variable.
constは再代入ができません。
const の制限とよくある誤解
constで宣言された変数は再代入ができないだけであり、中身(オブジェクトや配列の要素)は変更可能です。
const c = {x:1, y:2};
c.x = 10;
console.log(c) // {x: 10, y: 2}
constが「不変(immutable)」なのは参照自体であって、
その中身まで固定されるわけではありません。
使い分けの目安
- 
var 
 古いコードとの互換性目的で使われることが多い
 巻き上げにより、意図せず上書きされるリスクが高い
 現代のコードでは原則として使用しない
- 
let 
 ブロックスコープ内でのみ有効
 再宣言不可・再代入可
 一般的な変数に適する
- 
const 
 再代入不可
 定数や変更されない参照に使用するのが基本
letとconstを使うことで、varの持つ以下の問題を防げます。
- 巻き上げによる予期せぬ値の参照
- スコープの混乱
- 意図しない上書き・再宣言
また、変数がどこで変更されうるかが明確になるため、バグの発見もしやすくなります(可読性と保守性が向上)。
constを基本に使い、再代入が必要な場合のみletを使うという方針が最近では一般的です。
まとめ
var、let、constはいずれも変数宣言に使うが、挙動が異なる
varには巻き上げ(hoisting)があり、宣言前に変数が使えてしまう
letとconstにはTDZ(Temporal Dead Zone)があり、宣言前アクセスでエラーになる
実務ではletとconstが推奨される
関数を宣言前に使えるのは巻き上げによるもの
参考文献
徹底マスターJavaScriptの教科書(2017) 磯博
https://developer.mozilla.org/ja/docs/Glossary/Hoisting
