JavaScriptにおけるletとvarの違い

let宣言とは

JavaScriptにおいて変数を宣言する場合にはvar変数を使用しますが、ES6(ECMAScript6)に基づいてコーディングされたソースコードにはvar宣言の代わりにlet宣言が用いられている場合があります。

しかしながら、単純にvarがletに置き換わっているだけではないようなので、let宣言とvar宣言の違いについて調べてみました。

結果を先に言うと、let宣言とは「局所変数の宣言」ということでした。

let宣言は局所変数の宣言です

たとえば、次のようにJavaScriptを記述してあるHTMLがあったとします。

ファイル名はlet.htmlとでもしておきましょうか。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>let</title>
</head>
<body>
    <p id="a1"></p>
    <p id="b1"></p>
    <p id="a2"></p>
    <p id="b2"></p>

    <script>
        "use strict";

        var a = 1;
        var b = 2;

        if (true) {
            let a = 10;
            var b = 20;
            
            document.getElementById('a1').innerText = 'let a: ' + a;
            document.getElementById('b1').innerText = 'var b: ' + b;
        }

        document.getElementById('a2').innerText = 'var a: ' + a;
        document.getElementById('b2').innerText = 'var b: ' + b;
    </script>
</body>
</html>

これをブラウザで表示すると、このような表示になります。

let a: 10

var b: 20

var a: 1

var b: 20

局所変数とは

この出力結果がletとvarの違いです。

if文の中で変数aをletで宣言し直していますよね。このとき、変数aは「局所変数」として宣言されています。

対して変数bはif文の中でvarで宣言し直していますので、通常の変数のままです。

局所変数を宣言すると、変数のスコープを「それが使用されたブロック、文または式に限定」することができます。

つまり、ifやfunctionの内部でのみ反映される値を代入することができるわけです。

局所変数の使い方の注意点

上のソースコードでは、変数aとbの値をif文の内側と外側でそれぞれ出力させています。

変数bではif文の中でも外でも同じ「20」という値が出力されていますね。
一方で変数aではif文の中で出力している場合のみ「10」が出力され、if文の外では最初に代入した「1」が出力されます。

let宣言による局所変数では、変数のスコープがlet宣言を含む文や式に限定されるため、たとえばlet.html内のJavaScript部分を次のように書き換えるとエラーになります。

"use strict";

//var a = 1;
var b = 2;

if (true) {
  let a = 10;
  var b = 20;

  document.getElementById('a1').innerText = 'let a: ' + a;
  document.getElementById('b1').innerText = 'var b: ' + b;
}

document.getElementById('a2').innerText = 'var a: ' + a;
document.getElementById('b2').innerText = 'var b: ' + b;

上のソースコードではif文の外でvar宣言し、変数aに10を代入している部分をコメントアウトしました。

if文の中ではlet宣言により変数aが局所変数として宣言されているため、同じif文の中でしか参照できません。

そのため、下から2行目に書かれている「document.getElementById('a2').innerText = 'var a: ' + a;」の部分を実行しようとすると、「Uncaught ReferenceError: a is not defined」とConsoleに表示され、エラーとなります。

このように、局所変数のスコープ外から参照しようとしてエラーを起こさないように注意が必要です。

let宣言はいつ使えばいいのか

コンストラクタを仕様する際に let 文を用いることで、クロージャを使用せずにprivateなインターフェースを作成することができます。

letを用いて宣言されたjはvarとは性質が異なり、各forループ時の処理で別々のインスタンスとして定義されます。その性質によって、実行時にjを解決する時はそれぞれのインスタンスを参照するため、きちんと期待される動作が得られます。

この例を見てもわかるように、これまでfunctionをラップしてクロージャーを利用して解決していた手法よりも簡潔です。ECMAScript 6が導入された際に、主流の書き方となるかもしれません。

とあるように、let宣言による局所変数はクロージャーの代わりに使うようです。