ふみぽん's diary

技術的な備忘録が主のブログ

【JavaScript】varとletの違いを調べてみた

過去に以下のような記事を書きました。

fumipow2317.hatenablog.com

大変ありがたいことに以下のようなコメントをいただきました。ありがとうございますm( _ _ )m

なぜvarを使うとバグの温床になるのかという点を書いてもらうと、もっと良い記事になりそうです。

説明できないと思い、コード書いて試してみましたので記事にします。


varとletの違い

表形式で両者の違いをまとめてみます。

var let
再代入 できる できる
再宣言 できる できない
スコープ 関数スコープ  ブロックスコープ

ここでスコープについて補足です。

関数スコープとは、関数ごとに作られるスコープのこと

const func = () => {
 // === ここから関数スコープ ===
 var str = "umumum";
 console.log(str);

 ...(その他処理)

// === ここまで関数スコープ ===
}

ブロックスコープとは、ブロック{ }ごとに作られるスコープのこと


それでは まず、varを使って変数定義したサンプルコードから確認します。

const output = () => {
  var num = 10;
  console.log(num); // 10

  {
    var num = 99999999; // 再宣言
    console.log(num);  // 99999999

    var str = "ガムかむ"
  }

  console.log(num); // 99999999
  console.log(str); // ガムかむ
};
output();
// 10     (1行目)
// 99999999 (2行目)
// 99999999 (3行目)
// ガムかむ  (4行目)

関数outputを実行した結果の3行目に注目します。
varで宣言した変数numでは、再宣言が可能なのでvar num = 99999999;で変数numに格納された値が99999999となりました。

4行目にも注目します。 varで宣言した変数strは、関数outputで作られた関数スコープで使用できます。
そのためconsole.log(str);での出力が可能になっています。


次に、letを使って変数定義したサンプルコードを確認します。

const output = () => {
  let num = 10;
  console.log(num); // 10

  {
    let num = 99999999;
    console.log(num);  // 99999999

    let str = "ガムかむ"
  }

  console.log(num); // 10
  console.log(str); // not defined
};
output();
// 10     (1行目)
// 99999999 (2行目)
// 10     (3行目)
// Uncaught ReferenceError: str is not defined  (4行目)

関数outputを実行した結果の3行目に注目します。
let num = 99999999;はブロック内で使用できる変数numを定義しているだけです。
letでは再宣言はできないですし、ブロックスコープなのでnumの値が10 -> 99999999にはなりません。

同じく4行目にも注目します。
strが定義されていないというエラーになります。
原因は単純です。let str = "ガムかむ"で宣言している変数str
ブロックスコープ外のconsole.log(str);では参照できない変数だからです。


なぜvarは推奨されないのか

両者の違いを上記で確認したところで、本記事の本題です。 varが推奨されない理由としては、次のことが挙げられると思います。

  • 再宣言が可能であるために、予期せぬ変数値の書き換えが発生しやすくなる
    関数スコープが広いと、気付かずに同じ変数名を使用して
    別の目的で変数宣言してしまうこともあり得ると思います。
    そんなシーンでは予期しない書き換えが起こることがイメージできます。

letを使用すれば再宣言するとコンソールにエラーが吐かれるので気づくことができますね。


結論

というわけで

再代入の可能性がある変数を宣言する際は、letを使用することが推奨されます。