创建迭代器
- 如何设计一个迭代器
迭代器的本身是一个对象,这个对象有netx()
方法返回结果对象,这个结果对象有下一个返回值value
、迭代器完成布尔值done
,模拟创建一个简单迭代器:
function createIterator(items){
let i = 0;
return{
next(){
let done = (i>=items.length);
let value = !done ? items[i++] : undefined;
return{
done,
value
}
}
}
}
let arrayIterator = createIterator([1,2,3])
console.log(arrayIterator.next());
console.log(arrayIterator.next());
console.log(arrayIterator.next());
console.log(arrayIterator.next());
每次调用迭代器的next()
都会返回下一个对象,直到数据被用尽。
ES6中迭代器的编写过程类似,但引入了生成器对象,更简单的创建迭代器对象。
2. 创建迭代器
ES6封装了一个生成器(generator)用来创建迭代器。先然生成器是返回迭代器的函数,这个函数通过function
后的*号表示,并使用新的内部专用关键字yield
指定迭代器next()
方法的返回值
用ES6生成器创建一个迭代器:
function *createIterator(){
yield 123;
yield "mgd"
}
let someIterator = createIterator()
console.log(someIterator.next()); //{value: 123, done: false}
console.log(someIterator.next()); //{value: "mgd", done: false}
console.log(someIterator.next()); //{value: undefined, done: true}
使用yield
关键字可以返回任意值或者表达式,可以给迭代器批量添加元素:
function *createIterator(items){
for(let i in items){
yield items[i];
}
}
let someIterator = createIterator([123,'mge']);
console.log(someIterator.next()); //{value: 123, done: false}
console.log(someIterator.next()); //{value: "mge", done: false}
console.log(someIterator.next()); //{value: undefined, done: true}
由于生成器本身是函数,所以可添加到对象中,使用方式如下:
let obj = {
*createIterator(items){
for(let i in items){
yield items[i]
}
}
}
let someIterator = obj.createIterator([123,'mgd']);
console.log(someIterator.next()); //{value: 123, done: false}
console.log(someIterator.next()); //{value: "mgd", done: false}
console.log(someIterator.next()); //{value: undefined, done: true}
生成器函数的特点是:当执行完一句yield
语句后函数会自动停止执行,再次调用迭代器的next()
方法才会继续执行下一个yield
语句。
这种自动中止函数执行的能力衍生出很多高级用法,并提供了async/await
语法糖。
可迭代对象是个啥
- ES6中常用的集合对象(数组、Set、Map集合)和字符串都是可迭代对象
这些对象都有默认的迭代器和Symbol.iterator
属性。 - 通过生成器创建的迭代器也可以是可迭代对象
生成器默认会为Symbol.iterator
属性赋值。
1. Symbol.iterator
可迭代对象具有Symbol.iterator
属性,即具有Symbol.iterator
属性的对象都有默认迭代器。
我们可以用Symbol.iterator
来访问对象的默认迭代器,例如对于一个数组:
let list = [1,2,3]
let iterator = list[Symbol.iterator]();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
显然数组、Set/Map集合、字符串都是可迭代对象,而WeakSet/WeakMap集合(弱引用集合)是不可迭代的。
2. 创建可迭代对象
默认情况下,自定义的对象都是不可迭代的
通过生成器创建的迭代器也是一种可迭代对象,生成器会默认为Symbol.iterator
属性赋值
let collection = {
items:[1,2,3],
*[Symbol.iterator](){
for(let i of this.items){
yield i
}
}
}
const isIterator = obj => obj != null && typeof obj[Symbol.iterator] === 'function';
console.log(isIterator(collection)); //true
for(let item of collection){
console.log(item); //1 2 3
}
数组items
是可迭代对象,collection
对象通过给Symbol.iterator
属性赋值也成为可迭代对象。