制作器和迭代器这俩物品平常作为一个网页切图仔,一直都没有用到。感觉就是仅有在求职以前才大会物品。招聘面试通不过几日,再度看这些词一阵恍惚之间。
记忆能力衰退成这个样子么?较大的主要原因一定是用到减少了。之后呢?就是没真正意义上的了解他们。所以我对他们的认识常常会有以下这些:
1. 我经常把迭代器和制作器理解为截然不同的物品。
2. 我经常把for、forEach、map、reduce
和for of
混为一谈
3. 我经常把二维数组、类二维数组称之为可迭代对象
要来要想真正的记得它,增强自己的军械库,一定要搞明白这个东西才可以。
大家首先就是要弄明白哪些for of是干嘛用的。
业务代码的确应用不了,但如果不了解得话,等真到了可以使用的场景下的情况下,又是不是真的可以运用下去,乃至记起来呢?
for of 是干嘛用的
人人都知道一些定义for、forEach、map、reduce
这种是能够遍历数组的,for of
主要是用于赋值迭代更新对象。如下所示:
const arr = [1, 2, 3]
arr.forEach((item, index) => {
console.log(item) // 1, 2, 3
console.log(index) // 0, 1, 2
})
而巧的是for of
还可以遍历数组
for (let key of arr) {
console.log(key) // 1 2 3
}
将arr改变为const obj = { a: 1, b: 2, c: 3 }
时,它们都并没有赋值结果出来。
前者并没有反映,后面一种就会直接出错:TypeError: obj is not iterable
。翻译一下,种类不正确:obj 不是一个可迭代对象。
那么什么是可迭代对象呢?
可迭代对象是啥?
先来看看下面的事例:
const itemLi1 = document.getElementByTagName('li')
const itemLi2 = document.querySelectorAll('li')
for(let key of itemLi1) {
console.log(item)
}
for(let key of itemLi2) {
console.log(item)
}
换句话说HTMLCollection
和NodeList
是能够迭代更新目标。其它的可迭代对象有Array、map、set、string
这些。假如说类二维数组得话,是否迭代更新目标呢?
const arrLike = {
0: 1,
1: 2,
2: 3,
lenght: 3
}
for (let i = 0; i < arrLike.length; i ) {
console.log(arrLike[i]) // 1, 2, 3
}
for (let of arrLike) {
console.log(key) // uncachh TypeError: obj is not iterable
}
for循环打印出了相对应的结论,而for of 出错了。类二维数组并不是可迭代的目标。这确实是怎么回事?大家将类二维数组和HTMLCollection种类直接打印比较一下。
而类二维数组如下所示:
他们有一个很明显的不一样,可迭代对象的原型链里面是包含Symbol.iterator
的。而这就是让二维数组变为可迭代的主要原因。
换句话说,当目地对象原型链上边包含Symbol.iterator
时,它才算是可迭代对象。
目标是混乱的,混乱的东西了当然不能迭代更新
这儿应用到Symbol种类,他在MDN上边的理解就是用以形成全局性唯一的自变量。而可迭代对象是它的使用场景。受它启迪,大家在业务之中,必要时前面来生成一个唯一ID时,再度以前,一般都是创建一个UUID的功能来生成一个唯一ID。Symbol无需这么麻烦,直接用就行了。
由此可见,Array.prototype[Symbol.iterater]
这一函数公式封装形式了一些东西,促使for of
能将目标元素给直接打印。
换一句话而言,便是Array.prototype[Symbol.iterater] = function() {}
的落实生成一个迭代器目标。
换句话说,当Object.prototype
也是有[Symbol.iterater]
的办法时,for of
也可以赋值它呢?我们一起来试试看吧。
Object.ptotoype[Symbol.iterator] = function value() {}
这难道不是制作器的功效么?
制作器和迭代器之间的关系。
ES6帮我提升了一个制作器的函数公式。即然称为制作器,它形成的东西都是迭代器。
表达形式如下所示:
function * generation(iterableObject) {
for(let i = 0; i < iterableObject; i ) {
yield iterableObject[i]
}
}
由*
标记和yield
关键词构成。
当const iterator = generation([1, 2, 3])
, 其执行过程如下所示:
- iterator.next() ==> { value: 1, done: false }
- iterator.next() ==> { value: 2, done: false }
- iterator.next() ==> { value: 3, done: false }
- iterator.next() ==> { value: undefined, done: true }
到第四次,value为undefined
时,done为true(换句话说,当done为true时,value一定为undefined)。所以,yield
的功效有两种:
- 生成一个值,将这个值封装形式成一个目标,而且这个目标是
{ value: .., done: flase/true }
这种方式。 - 慢下来
可以明显的看出,制作器有一个功效,根据next这一插口,能够看见迭代更新的一个过程。
即然说制作器生成了一个迭代器,那是不是说制作器实行后结果就是一个迭代器呢?毕竟是迭代器,自然也就能够被for of
给赋值。
for (const key of generation([1, 2, 3]) {
console.log(key) // 1, 2, 3
}
果真能够。
经典面试题: 自身实现一个next
这种插口呢?
上边有了完成思路。通过一个标志符和一个分辨就可以使用ES5来用,如下所示代码片段。
function generation(iterableObj) {
let nextIndex = 0
function next() {}
return {
next: () => {
return nextIndex < iterableObj.length
? { value: iterableObj[nextIndex ], done: false }
: { value: undefined, done: true }
}
}
}
当nextIndex下于数组长度时,并没有迭代更新结束。
留意:nextIndex
要先跑nextIndex
,再自增。
什么是插口,后台管理给你一个url详细地址,这是网线端口。next是室内设计师让你封装形式的一个方法,通过你的用这种方法来实现上吧
yield
的两个关键点,因此next()也是一个插口,前面插口。简单来说,一个封装形式好的办法就是一个插口。
让非迭代更新目标也可以用for of 开展赋值
如同第一节常说,Symbol.iterator
的办法是迭代器的关键所在。那我们也可以给Object
初始化上要方式。即然此方法能让目标变为迭代器,就可以直接使用上边ES5完成next
方式的代码片段。
const obj = {
a: 1,
b: 2,
c: 3
}
Object.prototype[Symbol.iterator] = function value() {
const keys = Object.keys(Object(this))
let nextIndex = 0
function next() {
return nextIndex < keys.length
? { value: [keys[nextIndex], obj[keys[nextIndex ]]], done: false }
: { value: undefined, done: true }
}
return {
next
}
}
for (const [key, value] in obj) {
console.log(key)
}
for循环和for in之间的关系
for循环和for in 看见特别像,其实不过是同用了for
这一关键词,它们是JS模块最底层完成的东西了。和forEach、map
这种都是基于for循环的API不一样,他们要在通过在for循环之上的。
汇总
- 制作器generator实行结果就是一个迭代器
- 制作器能是也是由ES5达到的,并不是根据最底层API
- 是不是迭代器的关键在于
Symbol.iterator
方式
“打开AdminJS成长之路!这个是我参加「AdminJS日新的目标 · 2 月更文考验」第 18 天,查看更多活动规则”