JavaScript编程
JavaScript 循环
JavaScript 支持通过 for
和 while
关键字重复执行代码块。类似的行为也可以通过数据类型 Array
(以及类似的数据类型)的 forEach
方法实现。
for
循环
for
语句的语法为:
for (<初始表达式>; <条件表达式>; <最终表达式>) { <代码块> }
它的执行流程遵循以下规则:
- 初始表达式 执行一次,通常用于声明和初始化一个或多个变量,通常是整数类型的变量。有时,变量的声明会在
for
语句之前进行。 - 条件表达式 被评估。如果返回
true
,执行第 3 步。如果返回false
,循环终止。 - 代码块 执行。
- 最终表达式 执行,通常用于增加或减少与条件相关的变量。
- 循环重复,从第 2 步开始。
for (let i = 0; i < 10; i++) {
// 代码块
}
示例:展示从 0 到 10 的偶数平方,并显示这些数字的和。
"use strict";
const upperLimit = 10;
let sum = 0;
let tmpString = "";
for (let i = 0; i <= upperLimit; i++) {
sum = sum + i;
if (i % 2 === 0) {
tmpString += i * i + "; "
}
}
alert("The sum is: " + sum + ". The square numbers are: " + tmpString);
可选的语法部分
- 初始表达式、条件表达式和最终表达式是可选的。如果省略其中一个或多个,它们将被其他语句替代,以控制循环。例如:
"use strict";
// 无限循环,除非使用 'break' 来终止(见下文)
for (;;) {
// ...
break;
}
const answer = prompt("With which start value shall the loop begin?");
let i = Number(answer);
for (; i >= 0 && i < 10; i++) {
// 在循环外计算的起始值
}
for (let i = 0; i < 10;) {
// ...
if (true) { // 用任意其他条件控制递增
i++;
}
}
嵌套循环
for
循环可以嵌套使用。你可以在第一个(外部)循环的代码块中使用第二个(内部)循环。
"use strict";
const maxInner = 10;
const maxOuter = 4;
let myString = "";
for (let o = 1; o <= maxOuter; o++) {
myString = "";
// 小心。很容易混淆内外循环的变量。
for (let i = 1; i <= maxInner; i++) {
myString = myString + o * i + ", ";
}
alert(myString);
}
这种循环嵌套结构在其他循环构造中也是可以实现的。
continue
/ break
有时我们只希望部分代码或某个代码块执行。这可以通过一个或多个 if / else
语句实现。如果合适的话,可以通过关键字 continue
来简化这些条件语句。当 continue
被执行时,跳过代码块中剩余的部分,直接执行步骤 4 中的最终表达式。
示例:使用 continue
"use strict";
for (let i = 0; i <= 6; i++) {
if (i === 5) {
continue; // 跳过代码块的剩余部分
}
alert(i); // 0, 1, 2, 3, 4, 6
}
在这个简单的示例中,当 i
等于 5 时,跳过代码块的其余部分。当然,表达方式可以有所不同。更实际的例子可能是在数据库查询结果的循环中,跳过对某些特定状态的复杂处理。
break
关键字
break
关键字与 continue
类似,但更为严格。它不仅跳过代码块的其余部分,还会终止整个循环。
"use strict";
for (let i = 0; i <= 6; i++) {
if (i === 5) {
break; // 终止整个循环
}
alert(i); // 0, 1, 2, 3, 4
}
实际场景中,比如数据库查询结果的循环中,如果连接在循环中断开,使用 break
终止循环。
你可以在所有讨论过的循环形式中使用 continue
和 break
。
do {} while ()
语句的语法是:
do { <代码块> } while (<条件>);
它根据以下规则执行:
- 代码块执行。由于这是第一步,代码块至少会执行一次。如果你想确保某些操作在任何情况下都能执行时,这非常有用。
- 条件评估。如果条件返回
true
,则重复执行步骤 1。如果返回false
,循环终止。请注意,在此结构中没有专门的部分用于操作检查条件的变量。你必须在代码块内的其他语句中处理。
"use strict";
let counter = 100;
do {
counter++;
alert(counter); // ... 或其他日志记录
} while (counter < 10);
while () {}
while (<条件>) { <代码块> }
语法与 do { <代码块> }
while (<条件>)
非常相似。唯一的区别是 while
会在执行代码块之前检查条件,而 do
会在执行代码块之后检查条件。
"use strict";
let counter = 0;
while (counter < 10) {
counter++;
alert(counter); // 每次循环都会输出当前的 counter 值
}
for (x in Object) {}
这种语言构造用于遍历对象的属性。其语法为:
for (<变量> in <对象>) { <代码块> }
变量会依次接收对象中所有属性的键。对于每个键,代码块会执行一次。
"use strict";
const myObj = {firstName: "Marilyn", familyName: "Monroe", born: 1953};
for (const key in myObj) {
alert(key); // firstName, familyName, born
// alert(myObj[key]); // 如果想查看属性值
}
数组是特殊的对象,因此也可以在数组上使用 for..in
。对于数组,键是从 0 开始的整数,这正是 for..in
循环所提取的内容。
"use strict";
const myArray = ["certo", "uno", "dos", "tres"];
for (const key in myArray) {
alert(key); // 0, 1, 2, 3
// alert(myArray[key]); // 如果想查看值
}
数组也接受非数字键,例如:myArray["four"] = "cuatro";
。与 for..of
循环不同,for..in
循环会处理这种非数字键。
for (x of Array) {}
这种语言构造用于遍历数组。其语法为:
for (<变量> of <可迭代对象>) { <代码块> }
变量会依次接收数组中的所有值。对于每个值,代码块会执行一次。
这看起来与上面的 for..in
循环相似,但有显著的区别:
- 它返回数组的值,而不是键或索引。
- 它只对所有可迭代对象(如 Array、Map、Set 等)有效,而
object
数据类型不可迭代。 - 它只处理数值型的键,非数值型的键会被静默忽略。
"use strict";
const myArray = ["cero", "uno", "dos", "tres"];
myArray["four"] = "cuatro";
for (const myValue of myArray) {
alert(myValue); // cero, uno, dos, tres。没有输出 'cuatro',因为键是字符串。
}
总结:
for..in
用于遍历对象的键,可以用于数组,但会处理所有键(包括非数字键)。for..of
用于遍历数组的值,只处理数值型的键,忽略非数字键。
for..in
vs. for..of
for..in
和 for..of
之间的区别可以通过以下示例来总结:
"use strict";
const myObj = {firstName: "Marilyn", familyName: "Monroe", born: 1953};
const myArray = ["cero", "uno", "dos", "tres"];
myArray["four"] = "cuatro";
// for..of 不允许用于对象;只能用于 for..in
for (const x of myObj) {}; // 错误
for (const x in myArray) {
alert(x); // 0, 1, 2, 3, four
}
for (const x of myArray) {
alert(x); // cero, uno, dos, tres。没有 'cuatro'!
}
for..in
:用于遍历对象的属性或数组的索引(键)。对于对象,它遍历键;对于数组,它遍历索引。for..of
:用于遍历数组中的值,而不是键。对于数组的非数字键(如"four"
),for..of
会忽略它们。
Object.entries()
方法
如果你想要一个遍历对象的键和值的循环,使用 Object.entries()
方法比 for..in
和 myObj[key]
的组合更简单。Object.entries()
返回一个包含键和值的二维数组。
"use strict";
const myObj = {firstName: "Marilyn", familyName: "Monroe", born: 1953};
const myArray = ["cero", "uno", "dos", "tres"];
myArray["four"] = "cuatro";
for (const [key, val] of Object.entries(myObj)) {
alert(key + ' / ' + val);
}
for (const [key, val] of Object.entries(myArray)) {
alert(key + ' / ' + val); // 包含 'four / cuatro'
}
Object.entries()
和 Array.forEach()
方法并不是核心语言元素,它们是 Object
和 Array
数据类型的方法。
Array.forEach()
方法
Array
数据类型提供了 forEach()
方法,它用于遍历数组的元素,逐个返回每个元素。这个方法的特别之处在于,它接收一个函数作为参数,这使得它与其他 for
和 while
循环的区别在于它是基于回调函数的。
forEach()
方法调用的语法很简单:myArray.forEach(myFunction)
。可能令人困惑的是,函数调用可以有多种缩写形式。
示例:显式调用函数
"use strict";
// 函数定义(这里并未调用函数!)
function myFunction(element) {
alert("数组的元素是: " + element)
};
// 测试数组
const myArray = ['a', 'b', 'c'];
// 遍历数组,每次调用一次函数
myArray.forEach(myFunction);
函数调用的缩写形式
"use strict";
// 使用箭头函数语法
const myFunction =
(element) => {
alert("数组的元素是: " + element)
};
// 不换行的写法
// const myFunction = (element) => {alert("数组的元素是: " + element)};
const myArray = ['a', 'b', 'c'];
myArray.forEach(myFunction);
"use strict";
const myArray = ['a', 'b', 'c'];
// 直接将函数定义为 forEach() 的参数,这种函数称为“匿名函数”。
myArray.forEach((element) => {alert("数组的元素是: " + element)});
"use strict";
const myArray = ['a', 'b', 'c'];
// 在简单情况下,可以省略更多的语法元素
myArray.forEach(element => alert("数组的元素是: " + element));
具体使用哪种语法取决于你的偏好。
在许多情况下,调用的函数会执行副作用,例如日志记录。为了对所有数组元素进行计算,需要使用闭包技术。以下示例中,变量 sum
并未在外部上下文中定义,而是在匿名函数内定义的。
"use strict";
const myArray = [3, 0, -1, 2];
let sum = 0;
myArray.forEach(element => sum = sum + element);
alert(sum);
总结 forEach()
方法的规则:
- 该方法可以用于可迭代对象,如
Array
、Map
和Set
。Object
数据类型不可迭代。 - 它仅会遍历具有数字键的元素,这通常是数组的情况。