前端中迭代器的理解和手动封装一个迭代器
1.什么是迭代器?
迭代器就是为了实现对不同集合进行统一遍历操作的一种机制。它本身就是实现了一套迭代协议。
迭代协议:规定了迭代与实现的逻辑。
可能很多同学看着字面的意思还是很迷惑,啥玩意?别着急,咱们一步步的撸下去。
2.for-of 循环
2.1 针对数组的for-in 循环
回顾下for-in 这里直接上代码了;
let arr = ['a','b','c','d']
for(let attr in arr){
console.log(attr)
}
这里面我们可以看出来输出的是key的值,也就是数组的下标;
2.2 针对数组的for of循环
let arr = ['a', 'b', 'c', 'd']
for (let val of arr) {
console.log(val)
}
通过for of 我们可以看到输出的是对应的value的值。
2.3 针对对象的for in和for of循环。
let obj = {
a: 'a',
b: 'b',
c: 'c'
}
for (let attr in obj) {
console.log(attr, '这是for in循环对象')
}
for (let val of obj) {
console.log(val, '这是for of循环对象')
}
此时我们可以看到for in循环对象没问题,但是for of的时候报错,提示这个对象obj是不可迭代的。我们分别在控制台输出arr和obj分别看下,我们可以发现arr有Symbol.iterator方法,但是obj没有。
3.实现一个迭代器
我们要实现一个可迭代对象,只需要给它实现【Symbol.iterator】方法,而迭代器的实现过程就是迭代协议。下面我们就来手撸一个迭代器。
let obi = {
a: 1,
b: 2,
c: 3
};
obj[Symbol.iterator] = function(){
return {}
}
for(let val of obj){
}
此时我们运行下看看结果如何;
此时我们会发现这个对象缺少一个function。写迭代器一定要有一个next()方法,在next()里面必须有返回值;
let obj = {
a: 1,
b: 2,
c: 3
};
obj[Symbol.iterator] = function(){
return {
next(){
return {
done: false //done表示迭代是否完成 fasle 代表否
}
}
}
}
for(let val of obj){
}
此时在运行下,发现没有报错了,但是一直在执行,进入了一个死循环,舒服了。
下面我们来定义下规则,也就是迭代协议,就是你需要让它根据什么循环,就让它根据你的规定来循环。
let obj = {
a: 1,
b: 2,
c: 3
};
obj[Symbol.iterator] = function(){
// 迭代协议
let values = Object.values(obj)
let index = 0;
console.log(values)
return {
next(){
if(index>= values.length){
//表示循环完成
return {
// value: values[index++] 循环完成
done: true
}
}else{
return {
done: false,
value: values[index++]
}
}
}
}
}
for(let val of obj){
console.log(val)
}
此时执行就会发现,这个对象变成了可迭代对象。
我们可以模拟下它执行的过程。这里的代码我稍微修改下,为了测试它的执行过程;
let obj = {
a: 1,
b: 2,
c: 3
};
obj[Symbol.iterator] = function(){
// 迭代协议
let values = Object.values(obj)
let index = 0;
return {
next(){
if(index>= values.length){
//表示循环完成
return {
// value: values[index++] 循环完成
done: true
}
}else{
return {
done: false,
value: values[index++]
}
}
}
}
}
let values = obj[Symbol.iterator]();
console.log(values.next())
console.log(values.next())
console.log(values.next())
console.log(values.next())
// for(let val of obj){
// console.log(val)
// }
执行的结果:
到这我们就算实现了一个迭代器,for of就是相当于一直帮我们next()来执行这个迭代器。其中的迭代协议使我们自己定义的,现在只能输出value的值,那么我们可以让它同时输出key 和valule吗? 当然可以。
let obj = {
a: 1,
b: 2,
c: 3
};
obj[Symbol.iterator] = function(){
// 迭代协议
let keys = Object.keys(obj)
let index = 0;
return {
next(){
if(index>= keys.length){
//表示循环完成
return {
// value: keys[index++] 循环完成
done: true
}
}else{
return {
done: false,
value: {
key: keys[index],
value: obj[keys[index++]] //++是为了方便next时拿到下一项
}
}
}
}
}
}
let values = obj[Symbol.iterator]();
for(let val of obj){
console.log(val)
}
输出一下看看效果:
到这里,咱们的迭代器已经实现了,主要就是通过迭代协议来给对象封装一个Symbol.iterator方法,从而实现对象迭代的效果。下一篇我们将通过generator函数来实现封装一个async await异步执行方法。