1. for ... of
for ... of
语句可用于迭代iterable
对象。
所谓iterable
对象,指的是实现了Symbol.iterator
方法的对象,
该方法应当返回一个iterator
。
所谓iterator
,指的是实现了next
方法的对象,
该方法应当返回{value: anything ,done: boolean}
。
const iterable = {
[Symbol.iterator]: () => {
let i = 0;
return {
next: () => {
++i;
if (i == 3) {
return { value: i, done: true };
}
return { value: i, done: false };
}
};
}
};
for (const item of iterable) {
console.log(item); // 1 2
}
注:
(1)不迭代done:true
所对应的value
值。
(2)for ... of
的每次迭代都会新建一个作用域,
每次迭代item
在这个作用域中都是全新的。
如果该作用域中需要对item
重新赋值,
则可以用let
声明item
,for (let item of iterable) { }
。
2. 常见的iterable对象
Array,String,TypedArray,Map,Set,arguments ,
DOM collection(例如,NodeList)
let iterable;
// Array
iterable = [10, 20, 30];
for (const value of iterable) {
console.log(value); // 10 20 30
}
// String
iterable = 'foo';
for (const value of iterable) {
console.log(value); // "f" "o" "o"
}
// TypedArray
iterable = new Uint8Array([0x0a, 0x14, 0x1e]);
for (const value of iterable) {
console.log(value); // 10 20 30
}
// Map
iterable = new Map([['a', 10], ['b', 20], ['c', 30]]);
for (const entry of iterable) {
console.log(entry); // ['a', 10] ['b', 20] ['c', 30]
}
for (const [key, value] of iterable) {
console.log(value); // 10 20 30
}
// Set
iterable = new Set([10, 10, 20, 20, 30, 30]);
for (const value of iterable) {
console.log(value); // 10 20 30
}
// arguments
(function () {
for (const argument of arguments) {
console.log(argument); // 10 20 30
}
})(10, 20, 30);
注:
for ... of
中可以使用break
,continue
,return
和throw
。
3. 用于generator
generator返回的对象,既是一个iterator
,又是一个iterable
对象。
因此,generator的返回值可用于for ... of
。
function* fibonacci() {
let [prev, curr] = [0, 1];
while (true) {
[prev, curr] = [curr, prev + curr];
yield curr;
}
}
for (const n of fibonacci()) {
if (n > 10) {
break;
}
console.log(n);
}
注:
在for ... of
中使用break
中断的generator,会自动结束,
继续使用for ... of
,不能从中断处继续迭代。
const gen = function* () {
console.log('will yield 10');
yield 10;
console.log('will yield 20');
yield 20;
console.log('will yield 30'); // 不执行
yield 30;
};
const iter = gen();
for (const v of iter) {
console.log(`first for ... of: ${v}`);
if (v == 20) {
break; // 中断迭代,导致iter直接结束
}
}
for (const v of iter) { // iter已结束,将不再迭代
console.log(`second for ... of: ${v}`); // 不执行
}
输出:
will yield 10
first for ... of: 10
will yield 20
first for ... of: 20
4. for ... in 与 for ... of 的区别
for ... in
和for ... of
都可以用于迭代。
for ... in
用于迭代一个对象的所有可枚举属性,以这些属性被创建的顺序。
for ... of
用于在iterable
对象上进行迭代,以这个iterable
对象定义的迭代顺序。
Object.prototype.objCustom = function () { };
Array.prototype.arrCustom = function () { };
let iterable = [3, 5, 7];
iterable.foo = 'hello';
for (const i in iterable) {
console.log(i); // 0, 1, 2, "foo", "arrCustom", "objCustom"
}
for (const i in iterable) {
if (iterable.hasOwnProperty(i)) {
console.log(i); // 0, 1, 2, "foo"
}
}
for (const i of iterable) {
console.log(i); // 3, 5, 7
}