什么是迭代器?
之前看到网上有这样一个问题.问
for...in
和for...of
的区别,很多回答是,for...in
遍历不可迭代对象,for...of
遍历可迭代对象
看完一头雾水,什么叫可迭代对象,什么叫不可迭代对象,今天来专门做个解答,
我们知道再JS中
for...of
可以遍历数组,却不可以遍历对象,所以我们从数组和对象的区别入手, 首先JS是基于对象的脚本语言, 所有的数据类型的原型链最终都指向Object, 这样分析下来,一定是对象上缺少了某个属性才导致无法用for...of
遍历
通过访问Array.prototype我们发现数组的原型链上Symbol.iterator属性, 而且用符号作为属性名,肯定不简单, 我们就手动给对象添加这个属性,然后试试能否被for...of
遍历.
const user = {
name: 'Gege',
age: 18,
[Symbol.iterator]: () => {
console.log('hi')
}
}
for(let i of user) {
console.log(i)
}
果然有效
但是这有什么鸟用的? 而却控制台还给出了一个报错
VM248:1 Uncaught TypeError: Result of the Symbol.iterator method is not an object
通过报错内容我们知道, 浏览器告诉我们迭代器返回的结果不是一个对象, 那好,我们就给他返回一个对象! 还有一种生成迭代器的方法,就是在函数前面加个*
function *myIterator() {
yield 1;
yield 2;
}
我们不断地访问iter.next()
时,依次给我们返回下面这个对象.
当迭代器完毕之后最终返回
{ value: undefined, done: true }
参考这种方式 我们在迭代器里也返回这种格式的对象
const user = {
name: 'Gege',
age: 18,
[Symbol.iterator]: () => {
return {
*next() {
yield 'hi';
}
}
}
}
for(let i of user) {
console.log(i, 'www')
}
最终执行的结果是undefined
,而且由于无线循环我的浏览器也卡死了
总结一下, 我们的next方法不可以写成iterator函数,那么换一个思路
const user = {
name: 'Gege',
age: 18,
[Symbol.iterator]() {
console.log(this.age);
return {
next() {
return { value: 1, done: false }
}
}
}
}
for(let i of user) {
console.log(i, 'www')
}
这样的话可以成功访问到我们的值了,但是依然把我们的浏览器卡死了, 因为每次执行next都返回的{value: 1, done: false}
就会一直被认为迭代未完成, 类似于
vhile(true){
....
}
导致了无线循环
我们继续改造:
const user = {
name: 'Gege',
age: 18,
[Symbol.iterator]() {
const keys = Object.keys(this);
let idx = 0;
const _self = this;
return {
next() {
if (idx > keys.length - 1) {
return { value: undefined, done: true }
}
return { value: _self[keys[idx ++]], done: false }
}
}
}
}
大工告成!!!