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
}