如果学过设计模式或者java之类的肯定知道 iterator 是什么,在 Symbol.iterator
出现后,JS中也可以自己定义一个迭代器。
只要一个对象实现了正确的 Symbol.iterator
方法,那么它就可以被 for in
所遍历,如下所示:
var students = {}
students[Symbol.iterator] = function() {
let index = 1;
return {
next() {
return {done: index>100, value: index++}
}
}
}
for(var i of students) {
console.log(i);
}
仔细看上面的代码就会明白迭代器是如何工作的。当执行 for(var i of students)
的时候,其实是调用了 students[Symbol.iterator]()
方法,这个方法返回了一个iterator(迭代器)。迭代器有一个next方法,for循环会不断调用这个 iterator.next
方法来获取下一个值,直到返回值中的 done
属性为true的时候结束循环。
那么知道原理之后,我们可以自己来调用iterator.next来实现循环:
var students = {}
students[Symbol.iterator] = function() {
let index = 1;
return {
next() {
return {done: index>100, value: index++}
}
}
}
var iterator = students[Symbol.iterator]();
var s=iterator.next();
while(!s.done) {
console.log(s.value);
s=iterator.next();
}
上例中使用 iterator.next 和 while 结合实现了 for循环。
除了使用iterator 之外,我们还可以使用 yield 语法来实现循环,yield相对简单一些,只要通过 yield 语句把值返回即可:
let students = {
[Symbol.iterator]: function*() {
for(var i=0;i<=100;i++) {
yield i;
}
}
}
for(var s of students) {
console.log(s);
}
看到这里可能大家会怀疑 yield 和 iterator 到底是什么关系。这个我还不能确定,不过从用法上来说,可以基本认为 yield 只是 iterator 的语法糖,它其实就是最终生成了一个 iterator
,下面我们通过取出 yield 生成的 iterator 就可以看出来:
let students = {
[Symbol.iterator]: function*() {
for(var i=0;i<=100;i++) {
yield i;
}
}
}
var iterator = students[Symbol.iterator]();
var s=iterator.next();
while(!s.done) {
console.log(s.value);
s=iterator.next();
}
如上代码所示, yield 语句其实就是生成了一个 iterator ,完全和直接写 iterator 没区别,不过好处是使代码变得简洁明了,因此建议直接使用 yield 语法而不要费力的去写 iterator。
看完 上面的iterator 和 yield语法,其实看似神秘的循环也就很容易理解了。