aboutsummaryrefslogtreecommitdiff
path: root/files/zh-cn/web/javascript/guide/loops_and_iteration/index.html
blob: 9c82f4958862df8b17ff014714107fbd21fb627c (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
---
title: 循环与迭代
slug: Web/JavaScript/Guide/Loops_and_iteration
tags:
  - JavaScript
  - 循环
  - 指南
  - 语法
translation_of: Web/JavaScript/Guide/Loops_and_iteration
---
<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Control_flow_and_error_handling", "Web/JavaScript/Guide/Functions")}}</div>

<p class="summary">循环提供了一种快速和简单的方式去做一些重复的事。<a href="/en-US/docs/Web/JavaScript/Guide">JavaScript入门</a>的这个章节会介绍在JavaScript中存在哪些不同的迭代语句。</p>

<p>你可以把循环想成一种计算机化的游戏,告诉某人在一个方向上走X步,然后在另一个方向上走Y步;例如,“向东走5步”可以用一个循环来这样表达:</p>

<pre class="brush: js">var step;
for (step = 0; step &lt; 5; step++) {
  // Runs 5 times, with values of step 0 through 4.
  console.log('Walking east one step');
}
</pre>

<p>循环有很多种类,但本质上它们都做的是同一件事:它们把一个动作重复了很多次(实际上重复的次数有可能为 0)。各种循环机制提供了不同的方法去确定循环的开始和结束。不同情况下,某一种类型循环会比其它的循环用起来更简单。</p>

<p>JavaScript中提供了这些循环语句:</p>

<ul>
 <li>{{anch("for 语句")}}</li>
 <li>{{anch("do...while 语句")}}</li>
 <li>{{anch("while 语句")}}</li>
 <li>{{anch("labeled 语句")}}</li>
 <li>{{anch("break 语句")}}</li>
 <li>{{anch("continue 语句")}}</li>
 <li>{{anch("for...in 语句")}}</li>
 <li>{{anch("for...of 语句")}}</li>
</ul>

<h2 id="for_语句"><code>for</code> 语句</h2>

<p>一个 {{jsxref("statements/for","for")}} 循环会一直重复执行,直到指定的循环条件为 false。 JavaScript 的 for 循环,和 Java、C 的 for 循环,是很相似的。一个 for 语句是这个样子的:</p>

<pre class="syntaxbox">for ([initialExpression]; [condition]; [incrementExpression])
  statement
</pre>

<p>当一个 <code>for</code> 循环执行的时候,会发生以下过程:</p>

<ol>
 <li>如果有初始化表达式 <code>initialExpression</code>,它将被执行。这个表达式通常会初始化一个或多个循环计数器,但语法上是允许一个任意复杂度的表达式的。这个表达式也可以声明变量。</li>
 <li>计算 <code>condition</code> 表达式的值。如果 <code>condition</code> 的值是 true,循环中的语句会被执行。如果 <code>condition</code> 的值是 false,<code>for</code> 循环终止。如果 <code>condition</code> 表达式整个都被省略掉了,condition的值会被认为是true。</li>
 <li>循环中的 <code>statement</code> 被执行。如果需要执行多条语句,可以使用块(<code>{ ... }</code>)来包裹这些语句。</li>
 <li>如果有更新表达式 <code>incrementExpression</code>,执行更新表达式。</li>
 <li>回到步骤 2。</li>
</ol>

<h3 id="例子"><strong>例子</strong></h3>

<p>下面的函数包含一个含有 <code>for</code> 循环去计算一个滑动列表中被选中项目的个数(一个 {{HTMLElement("select")}} 元素允许选择多项)。<code>for</code> 循环声明了变量i并将它的初始值设为 0。它检查 <code>i</code> 是否比 <code>&lt;select&gt;</code> 元素中的选项数量少,执行了随后的 <code>if</code> 语句,然后在每次完成循环后,<code>i</code> 的值增加 1。</p>

<pre class="brush: html">&lt;form name="selectForm"&gt;
  &lt;p&gt;
    &lt;label for="musicTypes"&gt;Choose some music types, then click the button below:&lt;/label&gt;
    &lt;select id="musicTypes" name="musicTypes" multiple="multiple"&gt;
      &lt;option selected="selected"&gt;R&amp;B&lt;/option&gt;
      &lt;option&gt;爵士&lt;/option&gt;
      &lt;option&gt;布鲁斯&lt;/option&gt;
      &lt;option&gt;新纪元&lt;/option&gt;
      &lt;option&gt;古典&lt;/option&gt;
      &lt;option&gt;歌剧&lt;/option&gt;
    &lt;/select&gt;
  &lt;/p&gt;
  &lt;p&gt;&lt;input id="btn" type="button" value="选择了多少个选项?" /&gt;&lt;/p&gt;
&lt;/form&gt;

&lt;script&gt;
function howMany(selectObject) {
  var numberSelected = 0;
  for (var i = 0; i &lt; selectObject.options.length; i++) {
    if (selectObject.options[i].selected) {
      numberSelected++;
    }
  }
  return numberSelected;
}

var btn = document.getElementById("btn");
btn.addEventListener("click", function(){
  alert('选择选项的数量是: ' + howMany(document.selectForm.musicTypes))
});
&lt;/script&gt;

</pre>

<h2 id="do...while_语句"><code>do...while</code> 语句</h2>

<p>{{jsxref("statements/do...while", "do...while")}} 语句一直重复直到指定的条件求值得到假值(false)。 一个 do...while 语句看起来像这样:</p>

<pre class="syntaxbox">do
  statement
while (condition);
</pre>

<p><code>statement</code> 在检查条件之前会执行一次。要执行多条语句(语句块),要使用块语句(<code>{ ... }</code>)包括起来。 如果 <code>condition</code> 为真(true),<code>statement</code> 将再次执行。 在每个执行的结尾会进行条件的检查。当 <code>condition</code> 为假(false),执行会停止并且把控制权交回给 <code>do...while</code> 后面的语句。</p>

<h3 id="例子_2"><strong>例子</strong></h3>

<p>在下面的例子中, 这个 <code>do</code> 循环将至少重复一次,并且一直重复直到 <code>i</code> 不再小于 5。</p>

<pre class="brush: js">var i = 0;
do {
  i += 1;
  console.log(i);
} while (i &lt; 5);</pre>

<h2 id="while_语句"><code>while</code> 语句</h2>

<p>一个 {{jsxref("statements/while","while")}} 语句只要指定的条件求值为真(true)就会一直执行它的语句块。一个 <code>while</code> 语句看起来像这样:</p>

<pre class="syntaxbox">while (condition)
  statement
</pre>

<p>如果这个条件变为假,循环里的 <code>statement</code> 将会停止执行并把控制权交回给 <code>while</code> 语句后面的代码。</p>

<p>条件检测会在每次 <code>statement</code> 执行之前发生。如果条件返回为真, <code>statement</code> 会被执行并紧接着再次测试条件。如果条件返回为假,执行将停止并把控制权交回给 while 后面的语句。</p>

<p>要执行多条语句(语句块),要使用语句块 (<code>{ ... }</code>) 包括起来。</p>

<h3 id="例子_1"><strong>例子 1</strong></h3>

<p>只要 <code>n</code> 小于 3,下面的 <code>while</code> 循环就会一直执行:</p>

<pre class="brush: js">var n = 0;
var x = 0;
while (n &lt; 3) {
  n++;
  x += n;
}
</pre>

<p>在每次循环里, <code>n</code> 会增加 1,并被加到 <code>x</code> 上。所以, x 和 n 的变化是:</p>

<ul>
 <li>第一次完成后:<code>n</code> = 1,<code>x</code> = 1</li>
 <li>第二次完成后:<code>n</code> = 2,<code>x</code> = 3</li>
 <li>第三次完成后:<code>n</code> = 3,<code>x</code> = 6</li>
</ul>

<p>在三次完成后, 条件 <code>n &lt; 3</code> 的结果不再为真,所以循环终止了。</p>

<h3 id="例子_2_2"><strong>例子 2</strong></h3>

<p>避免无穷循环(无限循环)。保证循环的条件结果最终会变成假;否则,循环永远不会停止。因为条件永远不会变成假值,下面这个 while 循环将会永远执行:</p>

<pre class="brush: js">while (true) {
  console.log("Hello, world");
}</pre>

<h2 id="label_语句"><code>label</code> 语句</h2>

<p>一个 {{jsxref("statements/label","label")}} 提供了一个让你在程序中其他位置引用它的标识符。例如,你可以用 label 标识一个循环, 然后使用 <code>break</code> 或者 <code>continue</code> 来指出程序是否该停止循环还是继续循环。</p>

<p>label 语句的语法看起来像这样:</p>

<pre class="syntaxbox">label :
   statement
</pre>

<p><code>label</code> 的值可以是任何的非保留字的 JavaScript 标识符, <code>statement</code> 可以是任意你想要标识的语句(块)。</p>

<h3 id="例子_3"><strong>例子</strong></h3>

<p>在这个例子里,标记 <code>markLoop</code> 标识了一个 <code>while</code> 循环。</p>

<pre class="brush: js">markLoop:
while (theMark == true) {
   doSomething();
}</pre>

<p>举一个比较典型的例子,看完后即明白 Label 的应用:</p>

<p>未添加 Label:</p>

<pre class="brush: js">var num = 0;
for (var i = 0 ; i &lt; 10 ; i++) {   // i 循环
  for (var j = 0 ; j &lt; 10 ; j++) { // j 循环
    if( i == 5 &amp;&amp; j == 5 ) {
       break; // i = 5,j = 5 时,会跳出 j 循环
    } // 但 i 循环会继续执行,等于跳出之后又继续执行更多次 j 循环
  num++;
  }
}

alert(num); // 输出 95</pre>

<p>添加 Label 后:</p>

<pre class="brush: js">var num = 0;
outPoint:
for (var i = 0 ; i &lt; 10 ; i++){
  for (var j = 0 ; j &lt; 10 ; j++){
    if( i == 5 &amp;&amp; j == 5 ){
      break outPoint; // 在 i = 5,j = 5 时,跳出所有循环,
                      // 返回到整个 outPoint 下方,继续执行
    }
    num++;
  }
}

alert(num); // 输出 55</pre>

<p>使用 continue 语句,则可达到与未添加 label 相同的效果,但在这种有多层循环的情况下,循环的跳出进入流程更为明晰一些:</p>

<pre class="brush: js">var num = 0;
outPoint:
for(var i = 0; i &lt; 10; i++) {
  for(var j = 0; j &lt; 10; j++) {
    if(i == 5 &amp;&amp; j == 5) {
      continue outPoint;
    }
    num++;
  }
}
alert(num);  // 95</pre>

<p>从alert(num)的值可以看出,continue outPoint; 语句的作用是跳出当前循环,并跳转到outPoint(标签)下的 for 循环继续执行。</p>

<h2 id="break_语句"><code>break</code> 语句</h2>

<p>使用 {{jsxref("statements/break","break")}} 语句来终止循环,<code>switch</code>, 或者是链接到 label 语句。</p>

<ul>
 <li>当你使用不带 label 的 <code>break</code> 时, 它会立即终止当前所在的 <code>while</code><code>do-while</code><code>for</code>,或者 <code>switch</code> 并把控制权交回这些结构后面的语句。</li>
 <li>当你使用带 label 的 <code>break</code> 时,它会终止指定的带标记(label)的语句。</li>
</ul>

<p><code>break</code> 语句的语法看起来像这样:</p>

<pre class="syntaxbox">break [label];</pre>

<p>在语法中,被 <code>[]</code> 包裹的内容是可省略的,也就是 <code>label</code> 可以省略。若省略,则终止当前所在的循环或 <code>switch</code>;若不省略,则终止指定的 label 语句。</p>

<h3 id="例子_1_2"><strong>例子</strong> <strong>1</strong></h3>

<p>下面的例子循环数组里的元素,直到找到一个等于 <code>theValue</code> 的值:</p>

<pre class="brush: js">for (i = 0; i &lt; a.length; i++) {
  if (a[i] == theValue) {
    break;
  }
}</pre>

<h3 id="例子_2_终止一个_label"><strong>例子 2: </strong>终止一个 label</h3>

<pre class="brush: js">var x = 0;
var z = 0
labelCancelLoops: while (true) {
  console.log("外部循环: " + x);
  x += 1;
  z = 1;
  while (true) {
    console.log("内部循环: " + z);
    z += 1;
    if (z === 10 &amp;&amp; x === 10) {
      break labelCancelLoops;
    } else if (z === 10) {
      break;
    }
  }
}
</pre>

<h2 id="continue_语句"><code>continue</code> 语句</h2>

<p>{{jsxref("statements/continue","continue")}} 语句可以用来继续执行(跳过代码块的剩余部分并进入下一循环)一个 <code>while</code><code>do-while</code><code>for</code>,或者 <code>label</code> 语句。</p>

<ul>
 <li>当你使用不带 label 的 <code>continue</code> 时, 它终止当前 <code>while</code><code>do-while</code>,或者 for 语句到结尾的这次的循环并且继续执行下一次循环。</li>
 <li>当你使用带 label 的 <code>continue</code> 时, 它会应用被 label 标识的循环语句。</li>
</ul>

<p><code>continue</code> 语句的语法看起来像这样:</p>

<pre class="syntaxbox">continue [label];
</pre>

<h3 id="例子_1_3"><strong>例子 1</strong></h3>

<p>The following example shows a <code>while</code> loop with a <code>continue</code> statement that executes when the value of <code>i</code> is three. Thus, <code>n</code> takes on the values one, three, seven, and twelve.</p>

<pre class="brush: js">var i = 0;
var n = 0;
while (i &lt; 5) {
  i++;
  if (i == 3) {
    continue;
  }
  n += i;
  console.log(n);
}
//1,3,7,12
</pre>

<pre class="brush: js">var i = 0;
var n = 0;
while (i &lt; 5) {
  i++;
  if (i == 3) {
     // continue;
  }
  n += i;
  console.log(n);
}
// 1,3,6,10,15</pre>

<h3 id="例子_2_3"><strong>例子 2</strong></h3>

<p>一个被标签为 <code>checkiandj</code> 的语句包含了一个标签为 <code>checkj</code> 的语句。</p>

<p>如果遇到 <code>continue</code> 语句,程序会结束当前 <code>chechj</code> 的迭代并开始下一轮的迭代。</p>

<p>每次遇到 <code>continue</code> 语句时,<code>checkj</code> 语句会一直重复执行,直到 <code>checkj</code> 语句的条件为 <code>false</code></p>

<p>当返回<code> false</code> 后,将会执行 <code>checkiandj</code> 的剩余语句,<code>checkiandj</code> 会一直执行,直到 <code>checkiandj</code> 的条件为 <code>false</code></p>

<p><code>checkiandj</code> 的返回值为 <code>false</code> 时,将会执行 <code>checkiandj</code> 的下面的语句。</p>

<p>如果 <code>continue</code> 有一个标记 <code>checkiandj</code>, 程序将会从 <code>checkiandj</code> 语句块的顶部继续执行。</p>

<pre class="brush: js">var i = 0;
var j = 10;
checkiandj:
  while (i &lt; 4) {
    console.log(i);
    i += 1;
    checkj:
      while (j &gt; 4) {
        console.log(j);
        j -= 1;
        if ((j % 2) == 0) {
          continue checkj;
        }
        console.log(j + ' 是奇数。');
      }
      console.log('i = ' + i);
      console.log('j = ' + j);
  }</pre>

<h2 id="for...in_语句"><code>for...in</code> 语句</h2>

<p>{{jsxref("statements/for...in","for...in")}} 语句循环一个指定的变量来循环一个对象所有可枚举的属性。JavaScript 会为每一个不同的属性执行指定的语句。</p>

<pre class="syntaxbox">for (variable in object) {
  statements
}
</pre>

<h3 id="例子_4"><strong>例子</strong></h3>

<p>下面的函数通过它的参数得到一个对象和这个对象的名字。然后循环这个对象的所有属性并且返回一个列出属性名和该属性值的字符串。</p>

<pre class="brush: js">function dump_props(obj, obj_name) {
  var result = "";
  for (var i in obj) {
    result += obj_name + "." + i + " = " + obj[i] + "&lt;br&gt;";
  }
  result += "&lt;hr&gt;";
  return result;
}
</pre>

<p>对于一个拥有 <code>make</code><code>model</code> 属性的 <code>car</code> 对象来说,执行结果 <code>result</code> 是:</p>

<pre class="brush: js">car.make = Ford
car.model = Mustang
</pre>

<h3 id="数组"><strong>数组</strong></h3>

<p>虽然使用 <strong>for...in </strong>来迭代数组 {{jsxref("Array")}} 元素听起来很诱人,但是它返回的东西除了数字索引外,还有可能是你自定义的属性名字。因此还是用带有数字索引的传统的 {{jsxref("statements/for","for")}} 循环来迭代一个数组比较好,因为,如果你想改变数组对象,比如添加属性或者方法,<strong>for...in </strong>语句迭代的是自定义的属性,而不是数组的元素。(译者注:下面的 <code>for...of</code> 语句,和 <code><a href="/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach">forEach()</a></code>,也是理想的选择。)</p>

<h2 id="for...of_语句"><code>for...of</code> 语句</h2>

<p>{{jsxref("statements/for...of","for...of")}} 语句在<a href="/zh-CN/docs/Web/JavaScript/Guide/iterable">可迭代对象</a>(包括{{jsxref("Array")}}{{jsxref("Map")}}{{jsxref("Set")}}{{jsxref("functions/arguments","arguments")}} 等等)上创建了一个循环,对值的每一个独特属性调用一次迭代。</p>

<pre class="syntaxbox">for (<em>variable</em> of <em>object</em>) {
  <em>statement
</em>}
</pre>

<p>下面的这个例子展示了 <code>for...of</code>{{jsxref("statements/for...in","for...in")}} 两种循环语句之间的区别。 <code>for...in</code> 循环遍历的结果是数组元素的下标,而 <code>for...of</code> 遍历的结果是元素的值:</p>

<pre class="brush:js">let arr = [3, 5, 7];
arr.foo = "hello";

for (let i in arr) {
   console.log(i); // 输出 "0", "1", "2", "foo"
}

for (let i of arr) {
   console.log(i); // 输出 "3", "5", "7"
}

// 注意 for...of 的输出没有出现 "hello"
// 译者:官方文档不知为何在此使用三个空格来缩进…
</pre>

<p>{{PreviousNext("Web/JavaScript/Guide/Control_flow_and_error_handling", "Web/JavaScript/Guide/Functions")}}</p>