let
文はブロックスコープの局所変数を宣言します。任意で値を代入して初期化できます。
構文
let var1 [= value1] [, var2 [= value2]] [, ..., varN [= valueN]];
引数
var1
,var2
, …,varN
- 変数の名前。任意の有効な識別子を指定できます。
value1
,value2
, …,valueN
- 変数の初期値。任意の有効な式を指定できます。
説明
let
を使用することで、変数のスコープをそれが使用されたブロック、文または式に限定することができます。これは var
キーワードとは異なり、グローバル変数を定義したり、ブロックスコープに留まらない関数全体でのローカル変数を定義したりしません。
スコーピングのルール
let
で定義された変数では、自身が定義されたブロックがスコープになります。そのブロックに含まれている全てのサブブロックでも同様です。この点において let
のふるまいは var
にとてもよく似ています。主に違うのは、 var
で定義された変数のスコープはそれを含んでいる関数全体になるということです。次のコードはその例です。
function varTest() { var x = 31; if (true) { var x = 71; // 同じ変数です! console.log(x); // 71 } console.log(x); // 71 } function letTest() { let x = 31; if (true) { let x = 71; // 異なる変数 console.log(x); // 71 } console.log(x); // 31 }
内部関数でのクリーンなコード
let
は、しばしば内部関数で使用されるとコードをクリーンにします。
var list = document.getElementById("list"); for (let i = 1; i <= 5; i++) { let item = document.createElement("li"); item.appendChild(document.createTextNode("Item " + i)); item.onclick = function (ev) { console.log("Item " + i + " is clicked."); }; list.appendChild(item); }
上述の例は、5 つの(匿名)内部関数のインスタンスが 5 つの異なる変数 i
のインスタンスを参照するため、意図したとおりに動作します。let
を var
で置き換えた場合、すべての内部関数は i
の同じ最終値 6 を 返すため、意図したとおりに動作しないことに注意してください。また、我々は、各ループのスコープに新しい要素を生成するコードを移動することによって、ループ周りのスコープをクリーンに保つことができます。
var
とは異なり、プログラムのトップレベルと関数で、グローバルオブジェクト上にプロパティを生成しません。たとえば:
var x = 'global'; let y = 'global'; console.log(this.x); // "global" console.log(this.y); // undefined
プライベートインターフェースのエミュレート
constructor で処理することで、クロージャを使用することなくプライベートインターフェースを生成するために let
ステートメントを使用できます:
var SomeConstructor; { let privateScope = {}; SomeConstructor = function SomeConstructor () { this.someProperty = "foo"; privateScope.hiddenProperty = "bar"; } SomeConstructor.prototype.showPublic = function () { console.log(this.someProperty); // foo } SomeConstructor.prototype.showPrivate = function () { console.log(privateScope.hiddenProperty); // bar } } var myInstance = new SomeConstructor(); myInstance.showPublic(); myInstance.showPrivate(); console.log(privateScope.hiddenProperty); // error
Temporal dead zone と let
に関するエラー
同じ関数かブロックスコープで同じ変数を再宣言すると
が発生します。SyntaxError
if (x) { let foo; let foo; // SyntaxError が投げられます。 }
ECMAScript 2015 では let
は変数をブロックの先頭へ引き上げます。しかし、その変数を宣言より前で参照することは ReferenceError
を引き起こします。ブロックの始めから変数宣言が実行されるまで、変数は "temporal dead zone" の中にいるのです。
function do_something() { console.log(foo); // ReferenceError let foo = 2; }
switch
文には1つのブロックしかないため、エラーを発生させてしまうかもしれません。
switch (x) { case 0: let foo; break; case 1: let foo; // 再宣言によって TypeError break; }
関数に渡されるパラメータと同じ変数名で let
を使用すると、for
ループ内で undefined
となります。
function go(n){ for (let n of n.a) { console.log(n); } } go({a:[1,2,3]});
そのほかの例
ブロックの中で使うなら、 let
の変数のスコープはそのブロックの中に制限されます。スコープが自身の宣言された関数全体になる var
との違いに注意してください。
var a = 1; var b = 2; if (a === 1) { var a = 11; // スコープはグローバル let b = 22; // スコープは if ブロック内 console.log(a); // 11 console.log(b); // 22 } console.log(a); // 11 console.log(b); // 2
標準的でない let
拡張
let
ブロック
let
ブロックは Gecko 44 からサポートされなくなっています (バグ 1167029) 。
let
ブロックは、ブロックの外にある似た名前の変数の値に影響を与えずに、ブロックのスコープの中にある変数と値を関連づけるやり方を提供します。
構文
let (var1 [= value1] [, var2 [= value2]] [, ..., varN [= valueN]]) block;
説明
let
ブロックは変数に局所的なスコープをつけることを可能にします。コードブロックのレキシカルスコープに0個以上の変数を束縛するという動作をします。そのほかの点では、これはブロック文と全く同じです。let
ブロックの中で var
を使って宣言された変数のスコープは、依然として let
ブロックの外で宣言されたのと同じだということに特に注意してください。そのような変数はやはり関数スコープを持ちます。 let
ブロックを使うとき、 let
に続く括弧は必須です。括弧を忘れると構文エラーが発生します。
例
var x = 5; var y = 0; let (x = x+10, y = 12) { console.log(x+y); // 27 } console.log(x + y); // 5
このコードブロックについての規則は JavaScript のほかのコードブロックと同じです。 let
での変数宣言を使って、このブロック内のローカル変数を作ることができます。
スコープのルール
let
を使って定義された変数のスコープは let
ブロックそれ自体と、そこに含まれるほかのサブブロックですが、サブブロックで同名の変数が定義されているときを除きます。
let
式
let
式は Gecko 41 からサポートされなくなっています (バグ 1023609) 。
let
式は単一の式のみにスコープされた変数を作ることを可能にします。
構文
let (var1 [= value1] [, var2 [= value2]] [, ..., varN [= valueN]]) expression;
例
単一の式のみにスコープされた変数を作るために、 let
が使えます。
var a = 5; let(a = 6) console.log(a); // 6 console.log(a); // 5
スコープの規則
let
式があるとして:
let (decls) expr
expr を囲んで作られる暗黙のブロックがあります。
命名
"let" という名前がなぜ選ばれたかはこちらで確認できます。
仕様
仕様 | ステータス | コメント |
---|---|---|
ECMAScript 2015 (6th Edition, ECMA-262) Let and Const Declarations の定義 |
標準 | 初期定義。let 式や let ブロックは定義されていない。 |
ECMAScript 2017 Draft (ECMA-262) Let and Const Declarations の定義 |
ドラフト |
ブラウザー互換性
機能 | Chrome | Edge | Firefox (Gecko) | Internet Explorer | Opera | Safari |
---|---|---|---|---|---|---|
基本サポート | 41.0 | 12 | 44 (44) | 11 | 17 | ? |
Temporal dead zone | ? | 12 | 35 (35) | 11 | ? | ? |
let 式 |
未サポート | 未サポート | 未サポート | 未サポート | 未サポート | 未サポート |
let ブロック |
未サポート | 未サポート | 未サポート | 未サポート | 未サポート | 未サポート |
sloppy mode での許可 | 49.0 | ? | 44 (44) | ? | ? | ? |
機能 | Android | Android Webview | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile | Chrome for Android |
---|---|---|---|---|---|---|---|
基本サポート | ? | 41.0 | 44.0 (44) | ? | ? | ? | 41.0 |
Temporal dead zone | ? | ? | 35.0 (35) | ? | ? | ? | ? |
let 式 |
未サポート | ? | 未サポート | 未サポート | 未サポート | 未サポート | 未サポート |
let ブロック |
未サポート | ? | 未サポート | 未サポート | 未サポート | 未サポート | 未サポート |
sloppy mode での許可 | 未サポート | 49.0 | 44 (44) | ? | ? | ? | 49.0 |
Firefox 特有の注意
- SpiderMonkey 46 (Firefox 46 / Thunderbird 46 / SeaMonkey 2.43) 以下では、再宣言すると
SyntaxError
の代わりにTypeError
がスローされます バグ 1275240)。 - SpiderMonkey 44 (Firefox 44 / Thunderbird 44 / SeaMonkey 2.41) 以下では、
let
は<script type="application/javascript;version=1.7">
ブロック(またはより高いバージョン)にラップされた HTML のコードブロックでのみ使用可能であり、異なるセマンティックを持っていました。 Worker
コード内でのサポートは、dom.workers.latestJSVersion
フラグで隠されています (バグ 487070)。自由にlet
を使用できるバージョンから、このフラグは削除されます (バグ 1219523)。- SpIderMonkey での
let
の ES6 コンプライアンスは、バグ 950547 でトラックされています。