JavaScript | 基礎構文:変数・定数 – var を使わない理由

JavaScript
スポンサーリンク

まず結論:「新しく書くコードでは var はほぼ使わない」

JavaScript には変数宣言が 3 種類あります。

var
let
const
JavaScript

昔の JavaScript には var しかありませんでした。
その後、「危ない挙動が多すぎる」という反省から、
より安全で直感的な let / const が追加されました。

ここが重要です。
今から JavaScript を学ぶ人は、「変数は let / const を使う。var は“古い書き方”として基本使わない」
と考えて問題ありません。

では、なぜ var を使わないほうがいいのか、具体的な「怖さ」をかみ砕いて説明します。


理由1:var は「ブロックの中だけ」に閉じてくれない(スコープが広すぎる)

let / const は「{ } の中だけ」で有効

let / constブロックスコープ です。
つまり、{ } の中で宣言した変数は、その { } の中だけで有効です。

if (true) {
  let x = 10;
  console.log(x); // 10(ここでは使える)
}

console.log(x);   // エラー:x は定義されていない
JavaScript

これは直感的ですよね。
「この if の中だけで使いたい変数」は、外から触れないほうが安全です。

var は「関数スコープ」なので、ブロックを無視する

var関数スコープ です。
iffor{ } を「スコープ」として見てくれません。

if (true) {
  var y = 10;
  console.log(y); // 10
}

console.log(y);   // 10 (えっ…? ここでも見える)
JavaScript

if の中で宣言したはずの y が、
if の外でも普通に見えてしまいます。

もう少しハマりやすい例を出します。

for (var i = 0; i < 3; i++) {
  console.log("ループ内:", i);
}

console.log("ループ外:", i); // 3(i が外にも漏れている)
JavaScript

「ループのカウンター i」のつもりが、
関数の外(最悪グローバル)にまで生き続けてしまう ことがあります。

let を使った場合はこうです。

for (let i = 0; i < 3; i++) {
  console.log("ループ内:", i);
}

console.log("ループ外:", i); // エラー:i は定義されていない
JavaScript

直感どおり、「ループ専用の変数」として振る舞ってくれます。

ここが重要です。
var は「意図せず外側に変数が漏れる」リスクが高い。
スコープがゆるすぎて、変数名の衝突や上書きバグを招きやすい。
だから、ブロックスコープな let / const のほうが安全です。


理由2:var は「同じ名前で何度でも宣言できてしまう」(上書き事故の温床)

let / const は「二重宣言」を防いでくれる

let x = 1;
let x = 2; // エラー:「x はすでに宣言されています」
JavaScript

同じスコープで同じ名前の変数を宣言しようとするとエラーになります。
これは「うっかり上書きを防ぐ安全装置」です。

var は二重宣言しても怒らない

var y = 1;
var y = 2; // エラーにならない
console.log(y); // 2
JavaScript

サイレントに上書きされます。

小さいスクリプトならまだしも、
ファイルが大きくなったり、複数人で開発していると、

「自分が別の場所で同じ名前をもう使っていた」
「ライブラリの中でもその名前が使われていた」

といったことが起きやすく、
意図しない上書き が発生しやすくなります。

ここが重要です。
let / const は「その名前、もう使ってるよ」と教えてくれるが、var は黙って上書きしてしまう。
見つけにくいバグに直結するので、わざわざ var を選ぶ理由はほとんどありません。


理由3:var の「巻き上げ(ホイスティング)」が直感に反する

var は「宣言だけ上に持ち上がる」という挙動をする

次のコードを見てください。

console.log(a); // undefined(エラーではない)
var a = 10;
console.log(a); // 10
JavaScript

一見、「宣言前に使ってるからエラーになりそう」ですが、
var ではエラーになりません。

これは JavaScript の「ホイスティング」という仕様で、
内部的にはこう解釈されています。

var a;              // 宣言だけ先頭に“巻き上げ”られる
console.log(a);     // undefined
a = 10;
console.log(a);     // 10
JavaScript

つまり、「宣言だけ先に行われ、代入は元の位置で行われる」 という挙動です。

let / const は「宣言前に使うとちゃんとエラー」

console.log(b); // エラー:参照できない
let b = 10;
JavaScript

let / const にもホイスティング自体は起きているのですが、
「宣言前にアクセスするとエラーになる」という、
より安全な挙動 になっています(TDZ:Temporal Dead Zone)。

ここが重要です。
var のホイスティング挙動は、“後から宣言したのに前で使えてしまう”状態を作り、
コードの見た目と実際の実行順序のギャップを生みます。
初心者にとっては完全に罠なので、そもそも var に近づかないほうが安全です。


理由4:「for ループ × var」で有名なバグパターンが生まれる

典型的な罠の例

次のコードを見てください。

for (var i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log(i);
  }, 100);
}
JavaScript

「0, 1, 2 が表示されるかな?」と思うかもしれませんが、
実際の出力はこうなります。

3
3
3

理由は、

var i がブロックスコープではなく、
ループ全体で「1 つの i」を共有しているからです。

タイマーが実行される頃にはループが終わっていて、
i はすでに 3 になっているため、
どのコールバックから見ても i === 3 になってしまいます。

let なら直感どおりに動く

for (let i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log(i);
  }, 100);
}
JavaScript

この場合はちゃんと、

0
1
2

と表示されます。

let はブロックスコープなので、
各ループごとに“別々の i” が存在する と考えられます。

ここが重要です。
「ループの中で非同期処理を使う」ときに、var は直感とずれた振る舞いをしがち。
let を使えば、このよくあるバグパターンを自然と避けられます。


理由5:グローバル汚染の危険性が高い

var は「うっかりグローバル変数」を作りやすい

ブラウザ環境では、グローバルオブジェクト(window)に直接プロパティを追加するような形で、
変数が定義されることがあります。

var でグローバルに宣言すると:

var foo = 123;

console.log(window.foo); // 123(ブラウザの場合)
JavaScript

つまり、「グローバル名前空間」を汚染しやすい のです。

古いコードやライブラリがたくさん var を使っていると、
「どこで定義されたか分からないグローバル変数」が増え、
名前の衝突や予期せぬ上書きが起こりやすくなります。

let / const はグローバルに置いても window に乗らない(ブラウザの場合)

let bar = 456;

console.log(window.bar); // undefined
JavaScript

let / const はグローバルに書いても、
window のプロパティにはなりません(仕様上の違い)。

ここが重要です。
var は「グローバル汚染」「名前衝突」の危険性を高める。
大きなプロジェクトになればなるほど、var でのグローバル変数は地雷原になります。


それでも var を「知っておく」理由

古いコード・教材・記事に出てくる

「新しく書くコードでは var を使わない」
これはほとんどの現場で共通の方針です。

ただし、

  • 古い本・記事・ブログ
  • 古いライブラリのコード
  • 既存のレガシーなプロジェクト

では、いまだに var が大量に出てきます。

そのときに、

「なんか昔の書き方らしい」
「スコープがゆるい/ホイスティングするらしい」

というのを知っているだけで、
読んだときの理解が全然違ってきます。

「使わない」ためにも、ざっくり特徴だけは知る

ここまでの話を超ざっくりまとめると、

  • var
    • 関数スコープ(ブロックスコープではない)
    • 宣言の重複OK(上書き事故の元)
    • ホイスティングで宣言前に参照できてしまう(undefined)
    • for ループ+非同期でバグパターンの温床
    • グローバル汚染しやすい
  • 対して let / const
    • ブロックスコープで直感的
    • 二重宣言を防ぐ
    • 宣言前アクセスはエラー(安全)

という関係です。

ここが重要です。
「var はこういう危ない挙動をするから、今は使わない」という理由を知っておくことで、
古いコードを読むときに「なぜここでバグが起きているか」を理解しやすくなります。


まとめ:「var を使わない理由」を初心者目線で言い直すと

最後に、初心者向けに言い直すとこうです。

var は、昔 JavaScript にしかなかった変数の書き方。
でも、

  • ブロックの外にまで変数が漏れたり
  • 同じ名前で何度も宣言できたり
  • 宣言前に使えてしまったり(undefined)
    と、「人間の直感とズレる」「バグの元になる」挙動が多い。

その反省から、
振る舞いが素直で安全な let / const が後から用意された。

だから、今から JavaScript を書く人は、
「変数は let / const を使う。var は“古い危ない書き方”として読めれば十分」
というスタンスでいるのがベスト。

ここが本当に重要です。
あなたが「var を使わない」と決めること自体が、JavaScript で変なバグに巻き込まれないための一番簡単な防御策です。

もし余裕があれば、
小さなファイルを作って

  • varlet を if や for の中で試してみる
  • 宣言より前で console.log してみる

など、「実際に var の気持ち悪さ」を自分の目で確認してみてください。
一度体感すると、「ああ、これは確かに使いたくないな」と、腹の底から実感できるはずです。

タイトルとURLをコピーしました