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宣言による局所変数はクロージャーの代わりに使うようです。