前言
该篇文章会给你普及并且深入 for…in 和 for…of 的遍历的相关知识,还会给你介绍对象属性描述符和迭代器这两个知识点(简单概念,会在其他文章详讲),当你理解了这两个知识点后,你就会真正的明白 for…in 和 for…of 的使用场景,篇幅较长,希望大家能够坚持看下去,有所收获🎉🎉🎉
这里先提前告诉你主要内容:for…in 是用来枚举对象属性,for…of 用来遍历迭代器(有序结构数据)
一、对象属性描述符 - for…in
1. 获取对象属性描述符的 API
首先我们定义一个对象,并声明一个属性
const obj = { ikun: 666 }
获取属性描述符状态 API:Object.getOwnPropertyDescriptor()
Object.getOwnPropertyDescriptor(obj, 'ikun')
![image-20230111183133328](https://oss.zhishiyu.online/markdown_images/202301111831358.png)
这里我们可以看到,这里有几个属性:configurable、enumerable、value、writable
这里面只有 enumerable(可枚举)
会对 for...in
枚举有影响
其他属性该篇文章不做过深讲解,会写篇文章进行详讲
2. 设置对象属性描述符的 API
首先我们定义一个对象,并声明一个属性
const obj = { ikun: 666 }
获取属性描述符状态 API:Object.defineProperty()
Object.defineProperty(obj, 'rap', {
value: "music",
...,
})
3. enumerable
接下来通过 Object.defineProperty()
来给对象添加属性并配置
const obj = { ikun: 666 }
Object.defineProperty(obj, 'music', {
value: 200,
enumerable: false
})
Object.defineProperty(obj, 'basketball', {
value: "基尼太美",
enumerable: true
})
for (let key in obj) {
console.log(key) // ikun basketball
}
此时只能遍历出来,ikun, basketball
两个属性,但可以通过 in
来判断某个属性是否存在
'ikun' in obj // true
'music' in obj // true
'basketball' in obj // true
设置了 enumerable
属性后,无法被 for...in
遍历,但可以通过 in
来判断是否存在该属性
4. 原型链属性和方法的 enumerable
学过 JavaScript 高阶语法的同学都应该知道,当我们在获取对象属性的时候,他会现在自身上寻找有没有这个属性,自身没有这个属性,则会在原型链上面进行寻找
当我们在 for...in
枚举属性时,他也会把原型链上面的属性和方法一起枚举出来
但你们知道为啥在使用 for...in
的时候并没有遍历出来原型链上的属性和方法吗?无奖竞猜🎈
3
2
1
答案:原型链上面的属性和方法都被设置了 enumerable
为 false
5. 实验:for…in 会不会遍历原型链上面的属性
是吗?我不信?好小子,那我们可以来做一个实验,我们来获取所有原型链最终的归宿 Object.prototype 身上的 toString
方法身上的对象属性描述符
Object.getOwnPropertyDescriptor(Object.prototype, 'toString')
这里可以看到 toString
方法的 enumerable
被设置成了 false
接下来我们介绍一个新的 API Object.create()
用于将指定数据的原型链指向为其他数据
const obj_prototype = {
ikun: 666,
music: 'music',
basketball: '篮球'
}
const obj = Object.create(obj_prototype)
console.log(obj.__proto__) // {ikun: 666, music: 'music', basketball: '篮球'}
console.log(obj) // {}
obj 为空对象,而它的原型链上有数据
可以看到已经指向成功了,这时我们通过 for...in
进行枚举 obj
,看看结果如何
经过证实,这次信了吧?你要是还不信,就不让你吃我家鸽鸽下的蛋了🙄
二、迭代器 - for…of
1. 什么是迭代器
所有的有序结构(如数组、NodeList)内部都有内置的迭代器
该篇文章不会详讲迭代器,会在另一篇文章进行详讲,这里先说说大致内容
2. 有序结构
字符串
数组
NodeList 等 DOM 集合
Map
Set
arguments
注意:object 对象不属于迭代器,因为它内部的顺序不能够保障有序
3. 每个迭代器都会有一个属性 Symbol.iterator
实验证明有序数据存在 Symbol.iteraotr 属性:
let arr = [100,200,300]
console.log(arr[Symbol.iterator]) // ƒ values() { [native code] }
arr[Symbol.iterator]() // 出现如下内容,原型链身上会有一个叫 next 的方法
4. 为什么会存在 next 方法
next 方法就是用来帮助遍历的一个方法,每次调用这个 next 方法,就会返回一个对象,让我们调用四次
let arr = [100, 200, 300]
arr[Symbol.iterator]().next() // {value: 100, done: false}
arr[Symbol.iterator]().next() // {value: 200, done: false}
arr[Symbol.iterator]().next() // {value: 300, done: false}
arr[Symbol.iterator]().next() // {value: undefine, done: true}
arr 数组只存在三个元素,当第四次调用时 next() 返回的对象 done 则为了 true,表示终止没有内容了
现在我们使用 for...of
进行遍历 arr
迭代器(数组)
let arr = [100, 200, 300]
for (let n of arr){
console.log(n) // 100 200 300
}
So?你现在能猜到 for...of
的运行方式了吗?
该篇文章不会详 next,会在另一篇迭代器文章中进行详讲,这里先说说大致内容
5. 结论
当我们通过 for...of
进行遍历迭代器(有序结构)时,它会帮我我们调用内部构造器的 next
方法,每次调用通过返回对象的 done
属性判断是否,遍历完了全部数据
三、for…in
1. 介绍
for...in
语句以任意顺序枚举一个对象的除 Symbol
以外的可枚举属性,包括从原型链上继承的可枚举属性,一般用于枚举对象,但可以枚举数组(可以用但没必要)
回忆一下对象属性描述符上的 enumerable 属性
2. 使用示例
const obj = {
ikun: 'ikun',
rap: 'rap',
}
for (let key in obj) {
console.log(key) // ikun, rap
}
3. 枚举数组(可以但不适合)
使用 for in
去遍历数组,得到的 key
就是数组的索引 index
const arr = [
{ ikun: 'ikun' },
{ music: 'music' }
]
for (let key in arr) {
console.log(key) // 0 1
console.log(arr[key]) // { ikun: 'ikun' }, { music: 'music' }
}
一般都使用 for of
来进行遍历
4. for…in 如何中断循环
在 for in
中可以使用 break
或者 continue
去中断循环,不可以直接用 return
去中断循环
const arr = {
ikun: 'ikun',
music: 'music',
rap: 'rap'
}
// 中断循环
for (let key in obj) {
if (key === 'ikun') {
break
}
console.log(key) // music, rap
}
但如果你是杠精的话说:for in 可以使用 return 中断循环,那就只能将 for…in 放到函数中了,可以但没必要
5. 枚举带有 Symbol 的对象
const obj = {
ikun: 'ikun',
rap: 'rap',
[Symbol('music')]: '我是时长两年半的个人练习生',
}
for (let key in obj) {
console.log('obj.' + key + ' = 我是' + obj[key])
}
这里可以看到,不能够进行遍历 Symbol
属性
6. 如何枚举对象身上的 Symbol 属性
使用 Reflect.ownKeys()
获取指定对象身上的,所有属性包含(Symbol)
使用 Object.getOwnPropertySymbols()
获取指定对象身上的,所有 Symbol 属性
使用 Object.getOwnPropertyNames()
获取指定对象身上的属性,不包含(Symbol)属性
![image-20230111175812610](https://oss.zhishiyu.online/markdown_images/202301111758746.png)
四、for…of
1. 介绍
for...of
语句以顺序遍历有序结构的数据,详细情况,去看 [二、迭代器 - for…of](#二、迭代器 - for…of)
回忆一下迭代器上的 next 方法
2. 使用示例
var arr = ['ikun', 'singing', 'jump', 'rap', 'music', 'basketball'];
for(let item of arr){
console.log(item); // 'ikun', 'singing', 'jump', 'rap', 'music', 'basketball'
}
遍历数组里的每一项,并得到每一个元素
总结
for...in
专门用于枚举对象数据
- 内部原理通过
enumerable
对象属性描述符来判断是否可枚举的属性
for...of
专门用于遍历有序结构数据(数组,nodeList DOM集合等)
- 内部原理通过内置迭代器的
next
方法返回的对象来判断是否可以遍历
该篇文章知识点从慕课网双越老师的视频《快速掌握前端必会的7种设计模式》处习得,如有侵权,联系删除