likes
comments
collection
share

讲讲通俗易懂的迭代器

作者站长头像
站长
· 阅读数 52

前言

  • js中有多种可以被称之为集合的数据结构 (arr, obj, set, map);
  • 我们希望某些数据结构是可以被迭代的,于是官方就打造了一个属性Iterator,并设定具有Iterator属性的数据结构就是可迭代的;
  • 迭代器属性的值必须是一个对象,且对象中必须拥有next方法,该next每次被调用,就会返回一个对象 {done: false,value: x };
  • 拥有迭代器属性的数据结构才可以被 for-of 遍历;
  • for-of 遍历的其实是某结构上的迭代器对象。

正文

迭代器

  • 支持迭代器属性的数据结构:数组、列表、集合、队列、栈、树和图等。

数组拥有迭代器属性,因此数组可以通过for-of来实现对数组的遍历:

const color = ['red', 'green', 'blue', 'pink'];

for (let item of color ) {
    console.log(item);
}

讲讲通俗易懂的迭代器

迭代器中的[Symbol.iterator]通过手搓createIterator实现:

讲讲通俗易懂的迭代器

  • 迭代器属性的值为一个对象,所有创建的函数createIterator应该返回一个对象;
  • 并且返回的对象中必须拥有一个方法next;
  • next方法要要实现每次被调用返回一个对象,对象为{done: false,value: x }这种形式;
  • 通过done = i >= items.length;来获取调用next方法返回对象中的属性done的值,并且初始化i的值为0,也就是当items的长度大于i时,done为false,否则为true;
  • 再通过value = !done ? items[i++] : undefined;来获取调用next方法返回对象中的属性value的值,也就是当done为false时,表示还有元素没有遍历完,此时value为遍历到的元素的值,当done为true时,表示,已经全部遍历完,此时value为undefined。

代码实现:

// 可以创建一个可迭代的对象
function createIterator(items) {
    var i = 0;
    return {
        next: function() {
            var done = i >= items.length;
            var value = !done ? items[i++] : undefined;

            return {
                done: done,
                value: value
            }
        }
    }
}

var iterator =  createIterator([1, 2, 3]);

console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

var arr = [];
arr.iterator = createIterator();

讲讲通俗易懂的迭代器

const color = ['red', 'green' , 'blue'];

color[Symbol.iterator] = function() {
    return createIterator(color);
}

for (let value of color) {
    console.log(value);
}

讲讲通俗易懂的迭代器

const color = ['red', 'green' , 'blue'];
const [a, b, c] = color;

const [a, b, c] = color;的步骤:

  • let iter = color[Symbol.iterator]();
  • a = iter.next().value;
  • b = iter.next().value;
  • c = iter.next().value;

for of的实现原理

下面通过手写一个forOf来介绍一下forOf的实现原理:

  • 在函数forOf定义两个形参obj, cb,obj为传入的对象,cb为传入的回调函数;
  • 先判断obj[Symbol.iterator]是否存在,也就是判断传入的对象是否具有迭代器属性,因为具有迭代器属性才能通过for-of来遍历,不存在就报错;
  • 上面介绍过当调用next方法返回的对象的done属性为false时,就表示还没遍历完,所以通过obj[Symbol.iterator]().next();来获取返回的那个对象;
  • 判断该对象的done值,为false就执行回调函数cb,并将obj[Symbol.iterator]().next();来更新对象。

代码实现:

function forOf(obj, cb) {
  if (!(Symbol.iterator in obj)) {
     throw new TypeError(obj + ' is not iterable');
  }
 
  let iterator = obj[Symbol.iterator]();
  let res = iterator.next();
  while (!res.done) {
    cb(res.value);
    res = iterator.next();
  }
}

var colors = ['red', 'green', 'blue'];
forOf(colors, function(value) {
    console.log(value);
})

下面来介绍一个字节的题目,通过增加一些代码来实现下面的代码实现输出1,2:

var [a, b] = {a: 1, b: 2}; 

console.log(a, b);
  • 在Object的原型上定义一个[Symbol.iterator]函数,那没有迭代器属性的对象也可以拥有迭代器属性
  • 通过Object.values(this)来获取this中的value,并以一个数组的形式返回
  • 因为数组具有迭代器属性,那么这个时候就可以通过Object.values(this)[Symbol.iterator]();调用迭代器属性[Symbol.iterator]来得到[1, 2]
  • [a, b] = [1, 2]就可以得到想要的输出结果

结语

迭代器的知识点大家有理解了吗?如果有错误的地方或者不同的见解,欢迎大家的分享哦~

讲讲通俗易懂的迭代器

转载自:https://juejin.cn/post/7373876901440684058
评论
请登录