前言
迭代器是我们在学习ES6 中常常会被忽略的一个知识点,迭代器就是一种特殊的数据结构拥有一个(Symbol(Symbol.iterator))属性的就叫迭代器
认识迭代器
我们先来通过数组来见识一下迭代器,当我们在谷歌浏览器上定义一个数组,可以发现其隐式原型上就有迭代器这一属性
并且他还是一个函数类型的方法key是Symbol类型,值为函数类型,通过同样的方式我们能在浏览器测试发现当数组通过new Arrary()定义他会有迭代器这一属性,然而对于对象它自身隐式原型上没有迭代器这一属性。
for...in VS for...of
我们要想知道迭代器有什么作用,我们就要先了解for...in 和 for...of 之间有什么区别在js 中for...in这个语法很早就存在了,而for...of 是 es6中 新增的语法。我们通过for...of遍历数组是里面的i表示的数组的每一项并不是下标,我们通过有一段代码让for...of遍历数组,字符串和对象对其用法进行了解
// for ...in VS for ...of(只能遍历迭代器)
let arr = [1,2,3]
let str = 'hello'
let obj = {
name:'zyx',
age:18,
}
for(let i of arr){
console.log(i);//遍历数组
}
console.log('-----------------------');
for(let i of str){
console.log(i);//遍历的、字符串
}
console.log('-----------------------');
for(let i of obj){
console.log(i);//遍历的、字符串
}
我们可以看到当我们使用for...of遍历数组和字符串都能够正常遍历,但当我们遍历对象时会报obj不是一个迭代器,所以我们可以得到for...of能遍历所有的迭代器。那我们使用for...in 来遍历数组,字符串,对象时分别遍历的的是他的,下标和key 值,其实for...in可以遍历万物,和for...of完全不是一个同一个概念。那我们来好好聊一聊for...of是如何通过迭代器实现对迭代器的遍历的
for...of 原理实现
我们要想知道for...of代码是如何实现,那就先来看一看迭代器到底是个什么样的结构,并且是如何通过迭代器实现遍历的
const arr = [1, 2, 3]
const iterator = arr[Symbol.iterator]()
console.log(iterator);
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
根据上面代码实现我们可以看出迭代器是有数组的迭代器属性创建的一个对象,,我们在浏览器中运行上面代码我们能发现他里面有个 next 方法,当我们调用一次 next 方法后会遍历一次数组返回
{ value: 1, done: false } 当我们遍历到最后数组没有元素可以遍历了就会返回{ value: undefined, done: true }
我们根据上面对迭代器的使用来实现遍历数组,那我们根据其原理来手搓一个这个方法
function createIterator(array) {
let index = 0
return {
next: function() {
if (index < array.length) {
return {value: array[index++], done: false}
} else {
return {value: undefined, done: true}
}
}
}
}
const myIterator = createIterator([1, 2, 3])
console.log(myIterator.next());// {value: 1, done: false}
console.log(myIterator.next());// {value: 2, done: false}
console.log(myIterator.next());// {value: 3, done: false}
console.log(myIterator.next());// {value: undefined, done: true}
迭代器的应用:字节面试题:let [a,b] = {a:1,b:2}
我们介绍了那么久的迭代器,那如果我们遇到类型中不存在迭代器的数据类型时,想要遍历它那我们是不是就可以在它的拥有迭代器属性来实现
const obj = {
a: 1,
b: 2,
c: 3,
[Symbol.iterator]: function() {
let index = 0
return {
next: function() {
if (index < Object.keys(obj).length) {
return {value: Object.keys(obj)[index++], done: false}
} else {
return {value: undefined, done: true}
}
}
}
}
}
通过我们上面方法实现在Object这个数据类型中添加迭代器,实现当我们每遍历一遍像就会返回{value:xxx , done: false},直到遍历不不到值后就会返回{value: undefined, done: true} 我们通过在上表面代码使用for...of对其进行遍历来检测
for (const item of obj) {
console.log(item);
}
那我们如何通过迭代器实现对字节面试中let [a,b] = {a:1,b:2} 让数组中的a,b等于对象中的a,b的值呢?
Object.prototype[Symbol.iterator] = function () {
return Object.values(this)[Symbol.iterator]()
}
我们实际上实现这个操作使用到了取巧的方式实现的Object.values(this)得到的对象上的值是一个数组的形式,而数组身上是有迭代器的也就是我们将对象原型上添加的迭代器的结果取巧变为数组的迭代器的结果从而实现let [a,b] = {a:1,b:2}将a,b的值赋值为1,2。