JavaScriptの迭代器

76 阅读2分钟

什么是迭代器?

之前看到网上有这样一个问题.问for...infor...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)
}

图片.png

果然有效

但是这有什么鸟用的? 而却控制台还给出了一个报错

VM248:1 Uncaught TypeError: Result of the Symbol.iterator method is not an object

通过报错内容我们知道, 浏览器告诉我们迭代器返回的结果不是一个对象, 那好,我们就给他返回一个对象! 还有一种生成迭代器的方法,就是在函数前面加个*

function *myIterator() {
    yield 1;
    yield 2;
}

我们不断地访问iter.next()时,依次给我们返回下面这个对象.

图片.png 当迭代器完毕之后最终返回{ 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')
}

图片.png

最终执行的结果是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')
}

图片.png

这样的话可以成功访问到我们的值了,但是依然把我们的浏览器卡死了, 因为每次执行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 }
            }
        }
    }
}

图片.png

大工告成!!!