讲讲通俗易懂的迭代器
前言
- 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