aboutsummaryrefslogtreecommitdiff
path: root/files/ja/web/javascript/new_in_javascript/1.7/index.html
blob: 6750aa396b804e970eceead805096c9d5bd1887c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
---
title: JavaScript 1.7 の新機能
slug: Web/JavaScript/New_in_JavaScript/1.7
tags:
  - JavaScript
  - JavaScript_version_overviews
translation_of: Archive/Web/JavaScript/New_in_JavaScript/1.7
---
<div>
<div>{{jsSidebar("New_in_JS")}}</div>
</div>

<p>JavaScript 1.7 はいくつかの新機能、特に{{ 原語併記("ジェネレータ", "generators") }}{{ 原語併記("イテレータ", "iterators") }}{{ 原語併記("配列内包", "array comprehensions") }}{{ 原語併記("<code>let</code> 式", "<code>let</code> expressions") }}、および{{ 原語併記("分割代入", "destructuring assignment") }} を取り入れた言語アップデートです。<a href="/ja/New_in_JavaScript_1.6" title="ja/New_in_JavaScript_1.6">JavaScript 1.6</a> のすべての機能も含まれています。</p>

<p>JavaScript 1.7 のサポートは Firefox 2 に導入されました。</p>

<p>この記事に含まれるコードの例は JavaScript シェルから実験できます。<a href="/ja/Introduction_to_the_JavaScript_shell" title="ja/Introduction_to_the_JavaScript_shell">Introduction to the JavaScript shell</a> を読み、シェルのビルド方法と使い方を学んでください。</p>

<h2 id="JavaScript_1.7_.E3.82.92.E4.BD.BF.E3.81.86" name="JavaScript_1.7_.E3.82.92.E4.BD.BF.E3.81.86">JavaScript 1.7 を使う</h2>

<p>JavaScript 1.7 の一部の新機能を使うためには、JavaScript 1.7 が使いたいという宣言が必要です。HTML または XUL コードでは次のコードを使ってください。</p>

<pre><code>&lt;script type="application/javascript;version=1.7"/&gt;</code></pre>

<p><a href="/ja/Introduction_to_the_JavaScript_shell" title="ja/Introduction_to_the_JavaScript_shell">JavaScript シェル</a>を使うときは、コマンドラインで <code>-version 170</code> スイッチを使うか、<code>version()</code> 関数を使って使いたいバージョンを設定する必要があります。</p>

<pre><code>version(170);</code></pre>

<p>新しいキーワード "yield" と "let" を使用する必要のある機能は、既存のコードでそれらのキーワードが変数や関数として利用されている恐れがあるため、バージョン 1.7 と宣言しなければ利用できません。新しいキーワードを導入していない機能 (分割代入と配列内包) は、JavaScript のバージョン宣言なしに利用できます。</p>

<h2 id=".E3.82.B8.E3.82.A7.E3.83.8D.E3.83.AC.E3.83.BC.E3.82.BF.E3.81.A8.E3.82.A4.E3.83.86.E3.83.AC.E3.83.BC.E3.82.BF" name=".E3.82.B8.E3.82.A7.E3.83.8D.E3.83.AC.E3.83.BC.E3.82.BF.E3.81.A8.E3.82.A4.E3.83.86.E3.83.AC.E3.83.BC.E3.82.BF">ジェネレータとイテレータ</h2>

<p>{{ 原語併記("繰り返しの", "iterative") }} アルゴリズム (リストの各要素に同じ処理をしたり、同じデータセットに繰り返し計算を行うなど) を含むコードを開発する際、しばしば計算処理の間その値が維持される必要のある状態変数が使われます。伝統的には、繰り返しのアルゴリズムの介在変数を得るにはコールバック関数を使わなくてはなりません。</p>

<h3 id=".E3.82.B8.E3.82.A7.E3.83.8D.E3.83.AC.E3.83.BC.E3.82.BF" name=".E3.82.B8.E3.82.A7.E3.83.8D.E3.83.AC.E3.83.BC.E3.82.BF">ジェネレータ</h3>

<p>フィボナッチ数を計算するこの繰り返しアルゴリズムについて考えてみましょう:</p>

<pre class="brush:js">function do_callback(num) {
  document.write(num + "&lt;br&gt;\n");
}

function fib() {
  var i = 0, j = 1, n = 0;
  while (n &lt; 10) {
    do_callback(i);
    var t = i;
    i = j;
    j += t;
    n++;
  }
}

fib();</pre>

<p>このコードはアルゴリズムのそれぞれの繰り返しステップの処理を実行するのにコールバックルーチンを使っています。この場合、それぞれのフィボナッチ数は単純にコンソールに出力されます。</p>

<p>{{ 原語併記("ジェネレータ", "generators") }} および{{ 原語併記("イテレータ", "iterators") }} は相互に働き、新しく、より良くこれを実行する方法を提供します。ジェネレータを使って書かれたフィボナッチ数ルーチンがどうなっているか見てみましょう:</p>

<pre class="brush:js">function fib() {
  var i = 0, j = 1;
  while (true) {
    yield i;
    var t = i;
    i = j;
    j += t;
  }
}

var g = fib();

for (var i = 0; i &lt; 10; i++) {
  document.write(g.next() + "&lt;br&gt;\n");
}</pre>

<p><code>yield</code> キーワードを含む関数がジェネレータです。これを呼ぶと、ジェネレータの仮引数は実引数と結び付きますが、本体は実際には評価されません。代わりにジェネレータ・イテレータが返ってきます。ジェネレータ・イテレータの <code>next()</code> メソッドを呼び出すたびに、繰り返しのアルゴリズムが 1 回ずつ実行されます。それぞれのステップでの値は、<code>yield</code> キーワードで指定された値です。<code>yield</code> をアルゴリズムの繰り返しの範囲を示すジェネレータ・イテレータ版の <code>return</code> だと考えましょう。毎回 <code>next()</code> を呼び出すたび、ジェネレータのコードは <code>yield</code> の次の文から再開します。</p>

<p>あなたはジェネレータ・イテレータを、その <code>next()</code> メソッドを繰り返し呼び出すことで、あなたが望んだ結果の状態にたどりつくまで反復させられます。この例では、私たちが欲しいだけの結果を手に入れるまで <code>g.next()</code> を呼び出し続けることで、私たちはどれだけでも多くのフィボナッチ数を得ることができます。</p>

<h4 id=".E3.82.B8.E3.82.A7.E3.83.8D.E3.83.AC.E3.83.BC.E3.82.BF.E3.82.92.E6.8C.87.E5.AE.9A.E3.81.AE.E6.99.82.E7.82.B9.E3.81.8B.E3.82.89.E5.86.8D.E9.96.8B.E3.81.99.E3.82.8B" name=".E3.82.B8.E3.82.A7.E3.83.8D.E3.83.AC.E3.83.BC.E3.82.BF.E3.82.92.E6.8C.87.E5.AE.9A.E3.81.AE.E6.99.82.E7.82.B9.E3.81.8B.E3.82.89.E5.86.8D.E9.96.8B.E3.81.99.E3.82.8B">ジェネレータを指定の時点から再開する</h4>

<p>一度 <code>next()</code> メソッドを呼び出してジェネレータをスタートさせると、与えた特定の値を最後の <code>yield</code> の結果として扱わせる <code>send()</code> を使うことができます。その際ジェネレータはその次の <code>yield</code> のオペランドを返します。</p>

<p>ジェネレータを勝手な時点から始めることはできません。特定の値を <code>send()</code> する前に必ず <code>next()</code> でジェネレータをスタートさせなければなりません。</p>

<div class="note"><strong>注:</strong> 興味深い点として、<code>send(undefined)</code> を呼び出すことは <code>next()</code> を呼び出すことと等価です。しかし <code>send()</code> を呼び出す際、生まれたてのジェネレータを undefined 以外の値からスタートさせようとすると <code>TypeError</code> 例外を引き起こします。</div>

<h4 id=".E3.82.B8.E3.82.A7.E3.83.8D.E3.83.AC.E3.83.BC.E3.82.BF.E4.B8.AD.E3.81.A7.E3.81.AE.E4.BE.8B.E5.A4.96" name=".E3.82.B8.E3.82.A7.E3.83.8D.E3.83.AC.E3.83.BC.E3.82.BF.E4.B8.AD.E3.81.A7.E3.81.AE.E4.BE.8B.E5.A4.96">ジェネレータ中での例外</h4>

<p>投げさせたい例外の値を渡して <code>throw()</code> メソッドを呼び出すことで、ジェネレータに強制的に例外を投げさせることができます。この例外はその時点の中断されたジェネレータの文脈から、つまりあたかもその時点で一時停止されている <code>yield</code><code>throw <em>value</em></code> に置き換わったかのように投げられます。</p>

<p>もし投げられた例外の処理中に yield に遭遇しなかった場合、その例外は <code>throw()</code> の呼び出し元に伝播し、それ以降 <code>next()</code> を呼び出すと <code>StopIteration</code> が投げられます。</p>

<h4 id=".E3.82.B8.E3.82.A7.E3.83.8D.E3.83.AC.E3.83.BC.E3.82.BF.E3.82.92.E9.96.89.E3.81.98.E3.82.8B" name=".E3.82.B8.E3.82.A7.E3.83.8D.E3.83.AC.E3.83.BC.E3.82.BF.E3.82.92.E9.96.89.E3.81.98.E3.82.8B">ジェネレータを閉じる</h4>

<p>ジェネレータは自分自身を閉じさせる <code>close()</code> メソッドを持っています。ジェネレータを閉じることの効果は:</p>

<ol>
 <li>ジェネレータ内のアクティブなすべての <code>finally</code> 節が実行されます。</li>
 <li>もし <code>finally</code> 節が <code>StopIteration</code> 以外の例外を投げた場合、その例外は <code>close()</code> メソッドの呼び出し元に伝播されます。</li>
 <li>ジェネレータが終了します。</li>
</ol>

<h4 id=".E3.82.B8.E3.82.A7.E3.83.8D.E3.83.AC.E3.83.BC.E3.82.BF.E3.81.AE.E4.BE.8B" name=".E3.82.B8.E3.82.A7.E3.83.8D.E3.83.AC.E3.83.BC.E3.82.BF.E3.81.AE.E4.BE.8B">ジェネレータの例</h4>

<p>このコードは 100 回ループするごとに yield するジェネレータを走らせます。</p>

<pre class="brush:js">var gen = generator();

function driveGenerator() {
	if (gen.next()) {
		window.setTimeout(driveGenerator, 0);
	} else {
		gen.close();
	}
}

function generator() {
	while (i &lt; something) {
		/** 何か **/

		++i;
		/** 100 周ごとに yield **/
		if ((i % 100) == 0) {
			yield true;
		}
	}

	yield false;
}</pre>

<h3 id=".E3.82.A4.E3.83.86.E3.83.AC.E3.83.BC.E3.82.BF" name=".E3.82.A4.E3.83.86.E3.83.AC.E3.83.BC.E3.82.BF">イテレータ</h3>

<p>{{ 原語併記("イテレータ", "iterator") }} とは、データへの繰り返しの処理をしやすくする特別なオブジェクトのことです。</p>

<p>普通の使い方では、イテレータオブジェクトは「目に見えません」。つまりあなたはイテレータオブジェクトを明示的に操作する必要はなく、代わりに JavaScript の <a href="/ja/Core_JavaScript_1.5_Guide/Object_Manipulation_Statements" title="ja/Core_JavaScript_1.5_Guide/Object_Manipulation_Statements"><code>for...in</code><code>for each...in</code></a>を使うことで、オブジェクトのキーや値への繰り返し処理を自然と行うことができます。</p>

<pre class="brush:js">var objectWithIterator = getObjectSomehow();

for (var i in objectWithIterator) {
  document.write(objectWithIterator[i] + "&lt;br&gt;\n");
}</pre>

<p>もし独自のイテレータオブジェクトを実装したり、イテレータを直接操作する何か別の必要があったりするならば、あなたは <code>next</code> メソッドと <code>StopIteration</code> 例外、そして <code>__iterator__</code> プロパティについて知る必要があります。</p>

<p>あなたは <code>Iterator(<em>objectname</em>)</code> を呼び出すことで、あるオブジェクトのイテレータを生成することができますが、そのようなあるオブジェクトのイテレータは、そのオブジェクトの <code>__iterator__</code> メソッドを呼び出すことで見つけられます。もし <code>__iterator__</code> が存在しなければ、デフォルトのイテレータが生成されます。デフォルトのイテレータは、普通の <code>for...in</code><code>for each...in</code> のモデルに基づいて、オブジェクトのプロパティを yield します。もしあなたがカスタマイズしたイテレータを提供したいならば、<code>__iterator__</code> メソッドをあなたのカスタマイズしたイテレータのインスタンスを返すように上書きしてください。スクリプトからオブジェクトのイテレータを得るには、直接 <code>__iterator__</code> プロパティにアクセスせず <code>Iterator(<em>obj</em>)</code> を使ってください。後者は配列 (Array) に対しても使えますが、前者は使えません。</p>

<p>一度イテレータを手に入れれば、そのイテレータの <code>next()</code> メソッドを呼び出すことで簡単にオブジェクトの次の項目を取得することができます。もしデータが残っていない場合は、<code>StopIteration</code> 例外が投げられます。</p>

<p>ここに直接的なイテレータ操作の単純な例を示します:</p>

<pre class="brush:js">var obj = {name:"Jack Bauer", username:"JackB", id:12345, agency:"CTU", region:"Los Angeles"};

var it = Iterator(obj);

try {
  while (true) {
    print(it.next() + "\n");
  }
} catch (err if err instanceof StopIteration) {
  print("レコードの終わり。\n");
} catch (err) {
  print("不明なエラー: " + err.description + "\n");
}</pre>

<p>このプログラムの出力は次のようになります:</p>

<pre>name,Jack Bauer
username,JackB
id,12345
agency,CTU
region,Los Angeles
レコードの終わり。</pre>

<p>イテレータを生成する際、オプションとして 2 つ目の引数を指定することができます。この引数は真偽値で、<code>next()</code> メソッドを呼び出すごとにキーの方だけを返してほしいかどうかを示します。このパラメータはユーザー定義の<code>__iterator__</code> 関数に唯一の引数として渡されます。上のサンプルで <code>var it = Iterator(obj);</code><code>var it = Iterator(obj, true);</code> に変えると、以下のような出力になります:</p>

<pre>name
username
id
agency
region
レコードの終わり。
</pre>

<p>どちらの場合でも、データが返ってくる実際の順番はその実装によって変わります。データの順番は無保証です。</p>

<p>イテレータは、その中にあなたが気づいていないデータが含まれているかもしれないオブジェクトも含め、オブジェクト中のデータをスキャンする手軽な方法です。これは特に、アプリケーションが予想していないデータを保存する必要がある場合に便利です。</p>

<h2 id=".E9.85.8D.E5.88.97.E5.86.85.E5.8C.85" name=".E9.85.8D.E5.88.97.E5.86.85.E5.8C.85">配列内包</h2>

<p>{{ 原語併記("配列内包", "array comprehensions") }} は、配列のパワフルな初期化を実行する簡便な方法を提供するジェネレータの使い方です。例えば:</p>

<pre class="brush:js">function range(begin, end) {
  for (let i = begin; i &lt; end; ++i) {
    yield i;
  }
}</pre>

<p><code>range()</code><var>begin</var> から <var>end</var> までのすべての数値を返すジェネレータです。このように定義すると、私たちはこれを次のように使うことができます:</p>

<pre><code>var ten_squares = [i * i for each (i in range(0, 10))];</code></pre>

<p>これは新しい配列 <var>ten_squares</var> を、<code>0..9</code> の範囲にある値の平方を含むようあらかじめ初期化します。</p>

<p>あなたは配列を初期化する際、任意の条件文を使うことができます。もしある配列を 0 と 20 の間にある偶数が含まれるように初期化したいならば、次のコードを使うことができます:</p>

<pre>var evens = [i for each (i in range(0, 21)) if (i % 2 == 0)];</pre>

<p>JavaScript 1.7 以前では、これは次のようにコーディングしなければならないでしょう:</p>

<pre class="brush:js">var evens = [];

for (var i = 0; i &lt;= 20; i++) {
  if (i % 2 == 0)
    evens.push(i);
}</pre>

<p>配列内包はより一層コンパクトであるだけでなく、一度そのコンセプトに精通してしまえば、実際のところ読みやすいものです。</p>

<h3 id=".E3.82.B9.E3.82.B3.E3.83.BC.E3.83.97.E3.81.AE.E8.A6.8F.E5.89.87" name=".E3.82.B9.E3.82.B3.E3.83.BC.E3.83.97.E3.81.AE.E8.A6.8F.E5.89.87">スコープの規則</h3>

<p>配列内包は暗黙的な <code>let</code> 宣言と同様に、角カッコの内側にあるすべてを含んだその周りに暗黙的なブロックを持ちます。</p>

<p><em>Add details.</em></p>

<h2 id="let_.E3.82.92.E4.BD.BF.E3.81.A3.E3.81.9F.E3.83.96.E3.83.AD.E3.83.83.E3.82.AF.E3.82.B9.E3.82.B3.E3.83.BC.E3.83.97" name="let_.E3.82.92.E4.BD.BF.E3.81.A3.E3.81.9F.E3.83.96.E3.83.AD.E3.83.83.E3.82.AF.E3.82.B9.E3.82.B3.E3.83.BC.E3.83.97"><code>let</code> を使ったブロックスコープ</h2>

<p>データや関数のブロックスコープを管理する <code>let</code> を使うにはいくつかの方法があります:</p>

<ul>
 <li><strong><code>let</code></strong> は、あるブロックのスコープ内で、ブロックの外にある同じ名前の変数の値に影響を与えることなく、変数と値を関連付ける手段を提供します。</li>
 <li><strong><code>let</code></strong> は、1 つの式だけに対して変数スコープを確立することができます。</li>
 <li><strong><code>let</code> 定義</strong> は、その定義が行われたブロックにスコープが拘束された変数を定義します。この構文は <code>var</code> に対し使われる構文に非常によく似ています。</li>
 <li>また、<code>let</code> を使って <code>for</code> ループの文脈内でのみ存在しうる変数を確立することができます。</li>
</ul>

<h3 id="let_.E6.96.87" name="let_.E6.96.87"><code>let</code></h3>

<p><code>let</code> 文は変数に対するローカルスコープを提供します。<code>let</code> 文はコードのある 1 つのブロックのレキシカルスコープに 0 以上の変数を結びつけることによって働き、それ以外は<a href="/ja/JavaScript/Reference/Statements/block" title="ja/JavaScript/Reference/Statements/block">ブロック文</a>と全く同じです。特に、<code>let</code> 文の内側で <code>var</code> を使って定義された変数のスコープは、<code>let</code> 文の外側でそれが定義された場合と同じであり、そのような変数は従来通り関数スコープを持つことに注意してください。</p>

<p>例えば:</p>

<pre class="brush:js">var x = 5;
var y = 0;

let ( x = x + 10, y = 12 ) {
  print(x+y + "\n");
}

print( (x + y) + "\n" );</pre>

<p>このプログラムからの出力は次のようになるでしょう:</p>

<pre>27
5</pre>

<p>コードブロックに関するルールは JavaScript の他のコードブロックと同じです。<code>let</code> 宣言を使って確立されたブロック自身のローカル変数を持っているかもしれません。</p>

<div class="note"><strong>注:</strong> <code>let</code> 文の構文を使う時、<code>let</code> の後の丸カッコは必須です。これを入れないと構文エラーとなります。</div>

<div>{{ 英語版章題("Scoping rules 2") }}</div>

<h4 id=".E3.82.B9.E3.82.B3.E3.83.BC.E3.83.97.E3.81.AE.E8.A6.8F.E5.89.87_2" name=".E3.82.B9.E3.82.B3.E3.83.BC.E3.83.97.E3.81.AE.E8.A6.8F.E5.89.87_2">スコープの規則</h4>

<p><code>let</code> を使って定義された変数のスコープは、<code>let</code> ブロック自身とその内部に含まれるすべてのブロックです。ただしそれらのブロックが同じ名前で変数を定義している場合を除きます。</p>

<h3 id="let_.E5.BC.8F" name="let_.E5.BC.8F"><code>let</code></h3>

<p><code>let</code> を使ってある 1 つの式だけに対してスコープを持つ変数を確立することができます:</p>

<pre class="brush:js">var x = 5;
var y = 0;

document.write( let(x = x + 10, y = 12) x + y  + "&lt;br&gt;\n");
document.write( x + y + "&lt;br&gt;\n" );</pre>

<p>結果として出力されるのは:</p>

<pre>27
5</pre>

<p>この場合、変数 <var>x</var><var>y</var> のそれぞれ <code>x+10</code><code>12</code> との結び付きは、式 <code>x+y</code> に対してのみスコープを持ちます。</p>

<h4 id=".E3.82.B9.E3.82.B3.E3.83.BC.E3.83.97.E3.81.AE.E8.A6.8F.E5.89.87_3" name=".E3.82.B9.E3.82.B3.E3.83.BC.E3.83.97.E3.81.AE.E8.A6.8F.E5.89.87_3">スコープの規則</h4>

<p>以下の <code>let</code> 式があったとすると:</p>

<pre><code>let (<var>decls</var>) <var>expr</var></code></pre>

<p><var>expr</var> の周りに暗黙的なブロックが生成されます。</p>

<h3 id="let_.E5.AE.9A.E7.BE.A9" name="let_.E5.AE.9A.E7.BE.A9"><code>let</code> 定義</h3>

<p><code>let</code> キーワードはブロック内で変数を定義するのにも使うことができます。</p>

<div class="note"><strong>注:</strong> もしあなたがより興味深い <code>let</code> 定義の使用例を知っているならば、どうぞここに追加することを検討してみてください。</div>

<pre class="brush:js">if (x &gt; y) {
  let gamma = 12.7 + y;
  i = gamma * x;
}</pre>

<p><code>let</code> 文・式・定義はしばしば、内部関数が使われる際にコードを簡潔にさせることがあります。</p>

<pre class="brush:js">var list = document.getElementById("list");
for (var i = 1; i &lt;= 5; i++) {
  var item = document.createElement("LI");

  item.appendChild( document.createTextNode("Item " + i) );
  let j = i;

  item.onclick = function (ev) {
    alert("Item " + j + " is clicked.");
  };

  list.appendChild(item);
}</pre>

<p>上の例は、内部の無名関数の 5 つのインスタンスがそれぞれ変数 <code>j</code> の異なる 5 つのインスタンスを参照しているために、意図通りに動きます。もしこれで <code>let</code><code>var</code> に置き換えたり、変数 <code>j</code> を削除して単純に <code>i</code> を内部関数で使うと、これは意図通りには動かないことに注意してください。</p>

<h4 id=".E3.82.B9.E3.82.B3.E3.83.BC.E3.83.97.E3.81.AE.E8.A6.8F.E5.89.87_4" name=".E3.82.B9.E3.82.B3.E3.83.BC.E3.83.97.E3.81.AE.E8.A6.8F.E5.89.87_4">スコープの規則</h4>

<p><code>let</code> によって宣言された変数は、その定義があったブロックと、その変数が再定義されていないすべてのサブブロックにスコープを持ちます。この場合、<code>let</code><code>var</code> に非常によく似た働きをします。おもな違いは <code>var</code> 変数のスコープがそれを囲む関数全体であることです:</p>

<pre class="brush:js">function varTest() {
    var x = 31;
    if (true) {
        var x = 71;  // 同じ変数!
        alert(x);  // 71
    }
    alert(x);  // 71
}

function letTest() {
    let x = 31;

    if (true) {
        let x = 71;  // 違う変数
        alert(x);  // 71
    }
    alert(x);  // 31
}</pre>

<p><code>=</code> の右辺の式はブロックの内側になります。これは <code>let</code> 式や <code>let</code> 文のスコープの仕方と異なります:</p>

<pre class="brush:js">function letTests() {
    let x = 10;

    // let 文
    let (x = x + 20) {
        alert(x);  // 30
    }

    // let 式
    alert(let (x = x + 20) x);  // 30

    // let 定義
    {
        let x = x + 20;  // ここでの x は undefined と評価される
        alert(x);  // undefined + 20 ==&gt; NaN
    }
}</pre>

<p>プログラムやクラス内では、<code>let</code><code>var</code> がするようにグローバルオブジェクトのプロパティを生成したりはせず、代わりにその文脈で文を評価する際に生成される暗黙的なブロックにプロパティを生成します。これが本質的に意味するのは、<code>let</code> はそれ以前に <code>var</code> を使って定義された変数を上書きできないということです。例えば:</p>

<pre class="brush:js">// FF 2.0 b1 ではうまく動きません。"global" ではなく "42" を返してしまいます。
var x = 'global';
let x = 42;
document.write( this.x + "&lt;br&gt;\n" );</pre>

<p>このコードによって表示される出力は "42" ではなく、"global" です。</p>

<p>{{ 原語併記("<b>暗黙的なブロック</b>", "implicit block") }} とは、波カッコで囲まれていないブロックのことで、JavaScript エンジンによって暗黙的に生成されます。</p>

<p>関数内で <code>eval()</code> によって実行された <code>let</code> は、<code>var</code> がするように variable object (activation object or innermost binding rib) にプロパティを生成しません。その代りに、そのプログラムで文を評価する際に生成される暗黙的なブロックにプロパティを生成します。これは <code>eval()</code> がプログラムに作用する性質と前述のルールによる結果です。</p>

<p>別の言い方をすれば、コードを実行するのに <code>eval()</code> を使う際、そのコードは独立したプログラムとみなされ、そのコードの周りに暗黙的なブロックを持つのです。</p>

<h3 id="for_.E3.83.AB.E3.83.BC.E3.83.97.E4.B8.AD.E3.81.A7.E3.81.AE_let_.E3.82.B9.E3.82.B3.E3.83.BC.E3.83.97.E5.A4.89.E6.95.B0" name="for_.E3.83.AB.E3.83.BC.E3.83.97.E4.B8.AD.E3.81.A7.E3.81.AE_let_.E3.82.B9.E3.82.B3.E3.83.BC.E3.83.97.E5.A4.89.E6.95.B0"><code>for</code> ループ中での <code>let</code> スコープ変数</h3>

<p><code>let</code> キーワードは単に <code>var</code> でやるようにして、<code>for</code> ループのスコープ内で局所的に変数を結びつけることにも使うことができます。</p>

<pre class="brush:js">// obj を追加する
var i = 0;

for ( let i = i; i &lt; 10; i++ )
    document.write(i + "&lt;br&gt;\n");

    for ( let [name,value] in obj )
        document.write("名前: " + name + ", 値: " + value + "&lt;br&gt;\n");</pre>

<h4 id=".E3.82.B9.E3.82.B3.E3.83.BC.E3.83.97.E3.81.AE.E8.A6.8F.E5.89.87_5" name=".E3.82.B9.E3.82.B3.E3.83.BC.E3.83.97.E3.81.AE.E8.A6.8F.E5.89.87_5">スコープの規則</h4>

<pre><code>for (let <var>expr1</var>; <var>expr2</var>; <var>expr3</var>) <var>statement</var></code></pre>

<p>この例で、<var>expr2</var><var>expr3</var><var>statement</var> は、<code>let <var>expr1</var></code> によって宣言されたブロックローカルな変数を含む暗黙的なブロックに囲まれます。これは上の 1 つ目のループで実証しています。</p>

<pre class="eval">for (let <var>expr1</var> in <var>expr2</var>) <var>statement</var>
for each(let <var>expr1</var> in <var>expr2</var>) <var>statement</var></pre>

<p>これら両方の場合では、それぞれ <var>statement</var> を含む暗黙的なブロックができます。1 つ目の方は上の 2 つ目のループで示しています。</p>

<h2 id=".E5.88.86.E5.89.B2.E4.BB.A3.E5.85.A5" name=".E5.88.86.E5.89.B2.E4.BB.A3.E5.85.A5">分割代入</h2>

<p>{{ 原語併記("分割代入", "destructuring assignment") }} は、配列やオブジェクトのリテラルの構造とそっくりの構文を使って、配列やオブジェクトからデータを抽出することを可能にします。</p>

<p>配列やオブジェクトのリテラル式は、データのアドホックな (その場限りの) 詰め合わせを作る簡単な方法を提供します。一度そのようなデータの詰め合わせを作ってしまえば、あなたはそれを使いたいように使うことができます。関数から返すことさえできます。</p>

<p>分割代入を使うと、次の節の例で示すようなさまざまな興味深いことができるようになりますが、特に便利なのは、一つの文によって全体の構造を読み込むことができるという点です。</p>

<p>この能力は Perl や Python などの言語に存在する機能に似ています。</p>

<h2 id=".E4.BE.8B" name=".E4.BE.8B"></h2>

<p>分割代入は使用例を通じて説明するのが一番なので、ここではあなたが通読して学ぶためのいくつかの例を紹介します。</p>

<h3 id=".E4.B8.80.E6.99.82.E5.A4.89.E6.95.B0.E3.81.AE.E4.BD.BF.E7.94.A8.E3.82.92.E9.81.BF.E3.81.91.E3.82.8B" name=".E4.B8.80.E6.99.82.E5.A4.89.E6.95.B0.E3.81.AE.E4.BD.BF.E7.94.A8.E3.82.92.E9.81.BF.E3.81.91.E3.82.8B">一時変数の使用を避ける</h3>

<p>分割代入を使えば、例えば値を交換することができます:</p>

<pre class="brush:js">var a = 1;
var b = 3;

[a, b] = [b, a];</pre>

<p>このコードを実行後、 <var>b</var> は 1 に、<var>a</var> は 3 になります。分割代入がなければ、2 つの値の交換には一時変数 (あるいは一部の低級言語では <a class="external" href="http://ja.wikipedia.org/wiki/XOR%E4%BA%A4%E6%8F%9B%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0">XOR 交換のトリック</a>) が必要になります。</p>

<p>同様に、3 つ以上の変数を順に交換することにも使えます。</p>

<pre class="brush:js">var a = 'o';
var b = "&lt;span style='color:green;'&gt;o&lt;/span&gt;";
var c = 'o';
var d = 'o';
var e = 'o';
var f = "&lt;span style='color:blue;'&gt;o&lt;/span&gt;";
var g = 'o';
var h = 'o';

for (lp = 0; lp &lt; 40; lp++) {
    [a, b, c, d, e, f, g, h] = [b, c, d, e, f, g, h, a];
    document.write( a + '' + b + '' + c + '' + d + '' + e + '' + f + '' + g + '' + h + '' + "&lt;br /&gt;");
}</pre>

<p>このコードを実行すると、変数が循環する様子をカラフルな視覚情報として見ることができます。</p>

<p>上で出てきたフィボナッチ数のジェネレータの例に戻ってみると、"i" と "j" の新しい値を単一のグループ代入文で計算することによって、一時変数 "t" を除去することができます。</p>

<pre>function fib() {
    var i = 0, j = 1;
    while (true) {
        yield i;
        [i, j] = [j, i + j];
    }
}

var g = fib();

for (let i = 0; i &lt; 10; i++)
  print(g.next());</pre>

<h3 id=".E8.A4.87.E6.95.B0.E3.81.AE.E5.80.A4.E3.82.92.E8.BF.94.E3.81.99" name=".E8.A4.87.E6.95.B0.E3.81.AE.E5.80.A4.E3.82.92.E8.BF.94.E3.81.99">複数の値を返す</h3>

<p>分割代入のおかげで、関数は複数の値を返すことができます。関数から配列を返すこと自体はいつでもできたものの、分割代入はさらなる柔軟性を提供します。</p>

<pre><code>function f() {
    return [1, 2];
}</code></pre>

<p>見ての通り、すべての返り値を角カッコで囲んだ、配列に似た構文を使ってその結果を返します。この方法で任意の数の返り値を返すことができます。この例では、<code>f()</code> はその出力として <code>{{ mediawiki.external('1, 2') }}</code> を返します。</p>

<pre><code>var a, b;
[a, b] = f();
document.write ("A is " + a + " B is " + b + "&lt;br&gt;\n");</code></pre>

<p><code>['a, b'] = f()</code> というコマンドは、関数の返り値を角カッコ中の変数に順番に代入します。<var>a</var> は 1 にセットされ、<var>b</var> は 2 にセットされます。</p>

<p>また、返り値を配列として受け取ることもできます。</p>

<pre>var a = f();
document.write ( "A is " + a );</pre>

<p>この場合、<var>a</var> は値 1 と 2 を含む配列です。</p>

<h3 id=".E3.82.AA.E3.83.96.E3.82.B8.E3.82.A7.E3.82.AF.E3.83.88.E3.82.92.E6.A8.AA.E6.96.AD.E3.81.97.E3.81.A6.E3.83.AB.E3.83.BC.E3.83.97.E3.81.99.E3.82.8B" name=".E3.82.AA.E3.83.96.E3.82.B8.E3.82.A7.E3.82.AF.E3.83.88.E3.82.92.E6.A8.AA.E6.96.AD.E3.81.97.E3.81.A6.E3.83.AB.E3.83.BC.E3.83.97.E3.81.99.E3.82.8B">オブジェクトを横断してループする</h3>

<p>オブジェクトからデータを取り出すために、分割代入を使うこともできます:</p>

<pre class="brush:js">let obj = { width: 3, length: 1.5, color: "orange" };

for (let[name, value] in Iterator(obj)) {
    document.write ( "Name: " + name + ", Value: " + value + "&lt;br&gt;\n" );
}</pre>

<p>これは、オブジェクト <var>obj</var> の全てのキー/値の組についてループされ、それらの名前と値を表示します。この場合、出力は以下のようになります:</p>

<pre>Name: width, Value: 3
Name: length, Value: 1.5
Name: color, Value: orange</pre>

<p><code>obj</code> を囲む <code>Iterator()</code> は、JavaScript 1.7 では必須ではありません。しかし、<a href="/ja/New_in_JavaScript_1.8" title="ja/New_in_JavaScript_1.8">JavaScript 1.8</a> では必須になるでしょう。これは配列での分割代入を可能にするためです({{ Bug(366941) }} を参照)。</p>

<h3 id=".E3.82.AA.E3.83.96.E3.82.B8.E3.82.A7.E3.82.AF.E3.83.88.E3.81.AE.E9.85.8D.E5.88.97.E3.82.92.E6.A8.AA.E6.96.AD.E3.81.97.E3.81.A6.E3.83.AB.E3.83.BC.E3.83.97.E3.81.99.E3.82.8B" name=".E3.82.AA.E3.83.96.E3.82.B8.E3.82.A7.E3.82.AF.E3.83.88.E3.81.AE.E9.85.8D.E5.88.97.E3.82.92.E6.A8.AA.E6.96.AD.E3.81.97.E3.81.A6.E3.83.AB.E3.83.BC.E3.83.97.E3.81.99.E3.82.8B">オブジェクトの配列を横断してループする</h3>

<p>それぞれのオブジェクトから興味のあるフィールドだけを取り出しながら、オブジェクトの配列を横断してループすることもできます。</p>

<pre class="brush:js">var people = [
  {
    name: "Mike Smith",
    family: {
      mother: "Jane Smith",
      father: "Harry Smith",
      sister: "Samantha Smith"
    },
    age: 35
  }, {
    name: "Tom Jones",
    family: {
      mother: "Norah Jones",
      father: "Richard Jones",
      brother: "Howard Jones"
    },
    age: 25
  }
];

for each (let {name: n, family: { father: f } } in people) {
  document.write ( "Name: " + n + ", Father: " + f + "&lt;br&gt;\n" );
}</pre>

<p>これは、<var>name</var> フィールドを <var>n</var> に、<var>family.father</var> フィールドを <var>f</var> に抜き出し、それを出力しています。これは <var>people</var> 配列のそれぞれのオブジェクトに対し行われます。出力はこのようになります:</p>

<pre>Name: Mike Smith, Father: Harry Smith
Name: Tom Jones, Father: Richard Jones</pre>

<h3 id=".E4.B8.80.E9.83.A8.E3.81.AE.E8.BF.94.E3.82.8A.E5.80.A4.E3.82.92.E7.84.A1.E8.A6.96.E3.81.99.E3.82.8B" name=".E4.B8.80.E9.83.A8.E3.81.AE.E8.BF.94.E3.82.8A.E5.80.A4.E3.82.92.E7.84.A1.E8.A6.96.E3.81.99.E3.82.8B">一部の返り値を無視する</h3>

<p>あなたはまた、興味のない返り値を無視することもできます:</p>

<pre class="brush:js">function f() {
  return [1, 2, 3];
}

var [a, , b] = f();
document.write ( "A is " + a + " B is " + b + "&lt;br&gt;\n" );</pre>

<p>このコードを実行後、<var>a</var> は 1 になり、<var>b</var> は 3になります。値 2 は無視されます。あなたはこの方法で任意の(あるいは全ての)返り値を無視することができます。例えば:</p>

<pre><code>[,,,] = f();</code></pre>

<h3 id=".E6.AD.A3.E8.A6.8F.E8.A1.A8.E7.8F.BE.E3.81.AE.E3.83.9E.E3.83.83.E3.83.81.E3.81.8B.E3.82.89.E5.80.A4.E3.82.92.E5.8F.96.E3.82.8A.E5.87.BA.E3.81.99" name=".E6.AD.A3.E8.A6.8F.E8.A1.A8.E7.8F.BE.E3.81.AE.E3.83.9E.E3.83.83.E3.83.81.E3.81.8B.E3.82.89.E5.80.A4.E3.82.92.E5.8F.96.E3.82.8A.E5.87.BA.E3.81.99">正規表現のマッチから値を取り出す</h3>

<p>正規表現の <code><a href="/ja/JavaScript/Reference/Global_Objects/RegExp/exec" title="ja/JavaScript/Reference/Global_Objects/RegExp/exec"> exec()</a></code> メソッドがマッチを見つけると、正規表現の全体にマッチした部分文字列を 1 つ目の要素に格納し、続いて正規表現内で括弧に囲まれたグループにマッチした部分文字列を順に格納した配列を返します。分割代入を使うと、全体のマッチを使う必要が無ければそれを無視して、配列の一部分のみを取り出すことが簡単にできるようになります。</p>

<pre class="brush:js">// http / https / ftp 形式の URL にマッチする単純な正規表現
var parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url);
if (!parsedURL) return null;

var [, protocol, fullhost, fullpath] = parsedURL;</pre>