For 循环系列
for...of
循环是最新添加到 JavaScript 循环系列中的循环。它结合了其兄弟循环形式 for 循环
和 for...in 循环
的优势,可以循环任何可迭代(也就是遵守可迭代协议)类型的数据。默认情况下,包含以下数据类型:String、Array、Map 和 Set
,注意不包含 Object 数据类型(即 {})。默认情况下,对象不可迭代。
for 循环
const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
for (let i = 0; i < digits.length; i++) {
console.log(digits[i]);
}
for 循环的最大缺点是需要跟踪计数器
和退出条件
。使用变量 i
作为计数器来跟踪循环并访问数组中的值。我们还使用 digits.length
来判断循环的退出条件。虽然 for 循环在循环数组时的确具有优势,但是某些数据结构不是数组,因此并非始终适合使用 loop 循环。
for…in 循环
const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
for (const index in digits) {
console.log(digits[index]);
}
for...in
循环改善了 for 循环的不足之处,它消除了计数器逻辑和退出条件
。但是依然需要使用 index
来访问数组的值,这样很麻烦;几乎比之前更让人迷惑。
此外,当你需要向数组中添加额外的方法(或另一个对象)时,for…in 循环会带来很大的麻烦。因为 for...in 循环循环访问所有可枚举的属性
,意味着如果向数组的原型中添加任何其他属性,这些属性也会出现在循环中。
在循环访问数组时,不建议使用 for...in 循环。
注意, forEach
循环 是另一种形式的 JavaScript 循环。但是,forEach()
实际上是数组方法
,因此只能用在数组中
。也无法停止或退出 forEach 循环
。如果希望你的循环中出现这种行为,则需要使用基本的 for 循环。
for…of 循环
用于循环访问任何可迭代的数据类型
。编写方式和 for...in
循环的基本一样,只是将 in 替换为 of,可以忽略索引。
const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
for (const digit of digits) {
console.log(digit);
}
注意,建议使用复数对象名称来表示多个值的集合
。这样,循环该集合时,可以使用名称的单数版本来表示集合中的单个值。例如,for (const button of buttons) {…}
。
你可以随时停止或退出 for…of 循环。
const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
for (const digit of digits) {
if (digit % 2 === 0) {
continue;
}
console.log(digit);
}
不用担心向对象中添加新的属性。for…of 循环将只循环访问对象中的值。
Array.prototype.decimalfy = function() {
for (i = 0; i < this.length; i++) {
this[i] = this[i].toFixed(2);
}
};
const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
for (const digit of digits) {
console.log(digit);
}
/** 输出
0
1
2
3
4
5
6
7
8
9*/
slice()
方法返回一个从开始到结束(不包括结束
)选择的数组的一部分浅拷贝到一个新数组对象
。且原始数组不会被修改
。
arr.slice();
// [0, end]
arr.slice(begin);
// [begin, end]
arr.slice(begin, end);
// [begin, end)
begin
(可选),从该索引处开始提取原数组中的元素(从0开始)。如果该参数为负数,则表示从原数组中的倒数第几个元素开始提取,slice(-2)表示提取原数组中的倒数第二个元素到最后一个元素(包含最后一个元素)。如果省略 begin,则 slice 从索引 0 开始。end
(可选),在该索引处结束提取原数组元素(从0开始)。slice会提取原数组中索引从 begin 到 end 的所有元素(包含begin,但不包含end
)。slice(1,4) 提取原数组中的第二个元素开始直到第四个元素的所有元素 (索引为 1, 2, 3的元素)。如果该参数为负数, 则它表示在原数组中的倒数第几个元素结束抽取。如果 end被省略
,则slice 会一直提取到原数组末尾
。如果 end大于数组长度
,slice 也会一直提取到原数组末尾
。
展开运算符
展开运算符(用三个连续的点 ( ...
) 表示)是 ES6 中的新概念,使你能够将字面量对象展开为多个元素。
const books = ["Don Quixote", "The Hobbit", "Alice in Wonderland", "Tale of Two Cities"];
console.log(...books);
// 输出:Don Quixote The Hobbit Alice in Wonderland Tale of Two Cities
const primes = new Set([2, 3, 5, 7, 11, 13, 17, 19, 23, 29]);
console.log(...primes);
// 输出:2 3 5 7 11 13 17 19 23 29
上述例子发现数组和集合都扩展开了单个元素
。这有什么用?
展开运算符的一个用途是结合数组
const fruits = ["apples", "bananas", "pears"];
const vegetables = ["corn", "potatoes", "carrots"];
const produce = fruits.concat(vegetables);
console.log(produce);
// 输出: ["apples", "bananas", "pears", "corn", "potatoes", "carrots"]
注意,使用 const
声明的变量不能在同一作用域内重新声明或重新赋值。
这段代码实际上将 fruits
数组添加到 produce
数组的第一个索引处,将 vegetables
数组添加到第二个索引处。
const fruits = ["apples", "bananas", "pears"];
const vegetables = ["corn", "potatoes", "carrots"];
const produce = [...fruits, ...vegetables];
console.log(produce);
// 输出:[ 'apples', 'bananas', 'pears', 'corn', 'potatoes', 'carrots' ]
剩余参数
如果你可以使用展开运算符将数组展开为多个元素
,那么肯定有一种方式将多个元素绑定到一个数组中
吧?
剩余参数也用三个连续的点 ( ...
) 表示,使你能够将不定数量的元素表示为数组
。它在多种情形下都比较有用。
一种情形是将变量赋数组值
时。例如
const order = [20.17, 18.67, 1.50, "cheese", "eggs", "milk", "bread"];
const [total, subtotal, tax, ...items] = order;
console.log(total, subtotal, tax, items);
// 输出:20.17 18.67 1.5 ["cheese", "eggs", "milk", "bread"]
该代码将 order 数组的值分配给单个变量
。数组中的前三个值被分配给了 total、subtotal 和 tax,但是需要重点注意的是 items
。通过使用剩余参数,数组中剩余的值(作为数组)被分配给了 items
。
可变参数函数
剩余参数的另一个用例是处理可变参数函数
。可变参数函数是接受不定数量参数的函数。
例如,假设有一个叫做 sum() 的函数,它会计算不定数量
的数字的和。在运行期间,如何调用 sum() 函数?
sum(1, 2);
sum(10, 36, 7, 84, 90, 110);
sum(-23, 3000, 575000);
使用参数对象
function sum(...nums) {
let total = 0;
for(const num of nums) {
total += num;
}
return total;
}
不管传入函数的数字有多少个,应该始终返回数字的总和。参数对象
是像数组一样的对象,可以当做本地变量在所有函数中使用
。它针对传入函数的每个参数都包含一个值,第一个参数从 0 开始,第二个参数为 1,以此类推。
更多 ES6 内容,查看 《JavaScript ES6》 课程。