Skip to main content

ES6迭代器

迭代器由任意对象实现的接口,支持连续获取对象产出的每个值; 默认Symbol.iterator 属性。

消费方式#

  • 手动调用next()方法消费
  • for...of 循环自动消费(for( ; ; )、forEach)

迭代器模式, 可以支持迭代消费的数据结构(可迭代对象)

'12345'
[1, 2, 3, 4, 5]
new Map().set('a', 1).set('b', 2)
new Set().add(1).add(2).add(3)
arguments对象
NodeList等DOM集合类型

原生语言:for...of、数组结构、扩展操作符、Array.from()、创建集合、创建映射、Promise.all()、Promise.race()、yield*

let iter = [1, 2, 3, 4][Symbol.iterator]();
iter.next() // {done: false, value: 1}, 最后{value: undefined, done: true}

自定义迭代器#

class Counter {
constructor(limit) {
this.limit = limit
}
[Symbol.iterator]() {
let count = 1, limit = this.limit;
return {
next () {
if (count <= limit) {
return { done: false, value: count++ };
} else {
return { done: true, value: undefined };
}
}
}
}
}

考察点#

  1. 给出打印结果并说明原因
let arr = [1,2,3]
arr.name = 'Jack'
arr.length // 3
console.log(Object.keys(arr)) // ["0", "1", "2", "name"]
for(let i in arr) { console.log('in', i) } // 0, 1, 2, 3, name
for (let i of arr) { console.log(i) } // 1, 2, 3
  • for...in 是枚举全部属性
  • for...of 是迭代器
  1. 改造数据使得for...of可遍历出全部值

解决方法1:

let arr = [1,2,3]
arr.name = 'Jack'
// Symbol.iterator
arr[Symbol.iterator] = function () {
let index = 0;
const _this = this;
const keys = Object.keys(_this);
const len = keys.length;
return {
next() {
if (index < len) {
return {
value: _this[keys[index++]],
done: false
}
}
return {
value: null,
done: true
}
}
}
}
let iter = arr[Symbol.iterator]()
for (let i of arr) {
console.log(i)
}
// 1
// 2
// 3
// Jack

方式2: 生成器函数

let arr = [1,2,3]
arr.name = 'Jack'
// Symbol.iterator
arr[Symbol.iterator] = function* () {
const keys = Object.keys(this);
for (let i = 0; i < keys.length; i++) {
yield this[keys[i]]
}
}
let iter = arr[Symbol.iterator]()
for (let i of arr) {
console.log(i)
}
// 1
// 2
// 3
// Jack

https://gitee.com/daaasheng/my_code_block/commit/b589b41274619c291a7b711ddada1fb72bd65a0e

疑问#

  1. for (let item of arr) {iter.next()} 与 for(let item of iter) 区别?
  2. 提前终止, 出发迭代器是否重新开始