携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第 10 天,点击查看活动详情
start
- 前几天睡觉老梦到去面试,面试官让我说说
for...in
和for...of
的区别。 - 一次两次也就罢了,关键是一直梦到,而且更关键的是我还说不明白。
- 现在学还来得及嘛?手动狗头
for...in
先看看MDN 的说明吧
解释: for...in 语句以任意顺序迭代一个对象的除 Symbol 以外的可枚举属性,包括继承的可枚举属性。
思考:
-
任意顺序迭代 迭代的顺序是任意的,所以 MDN 后续文档又这么一句话
备注:for...in不应该用于迭代一个关注索引顺序的 Array。
-
除 Symbol 以外的可枚举属性 所以需要注意下,for...in 无法遍历 Symbol 类型的属性;
-
可枚举属性 是否可枚举,可以通过
Object.defineProperty()
属性enumerable
定义(默认 enumerable 为 false); 快速判断属性是否可枚举可通过Object.prototype.propertyIsEnumerable()
-
包括继承的可枚举属性 原型链上的可枚举属性也会被遍历到。
验证一下:
1.验证第一条 ”任意顺序迭代“
/* 我这里将属性值不为number类型的放在靠前的位置 */
var obj = {
4: 'string',
5: false,
6: function () {
console.log(1)
},
1: 1,
2: 2,
3: 3,
}
for (const key in obj) {
console.log(key, obj[key])
}
/*
1 1
2 2
3 3
4 string
5 false
6 [Function: 6]
*/
// for...in 遍历对象是按什么顺序遍历的? 有这么一个评论,仅供**参考**
// ES6 之前 Object 的键值对是无序的,所以遍历也无序可言。ES6 之后 Object 的键值对按照自然数、非自然数和 Symbol 进行排序,自然数是按照大小升序进行排序,其他两种都是按照插入的时间顺序进行排序。
2.验证第二条 “除 Symbol 以外的可枚举属性”
var obj = {
1: 11,
[Symbol('tomato')]: 'lazy', // 属性名直接写 Symbol表达式会报错,所以这里我用了中括号包裹一下。
name: '测试symbol',
}
for (const key in obj) {
console.log(key, obj[key])
}
/*
1 11
name 测试symbol
*/
3.验证第三条 “可枚举属性”
var obj = {
name: '测试可枚举属性',
}
for (const key in obj) {
console.log(key, obj[key])
}
/*
name 测试可枚举属性
*/
console.log(obj.propertyIsEnumerable('name')) // true
Object.defineProperty(obj, 'age', {
value: '18',
})
Object.defineProperty(obj, 'like', {
value: 'game',
enumerable: true,
})
console.log(obj.age) // 18
console.log(obj.like) // game
/* 验证enumerable默认为false */
console.log(obj.propertyIsEnumerable('age')) // false
console.log(obj.propertyIsEnumerable('like')) // true
for (const key in obj) {
console.log(key, obj[key])
}
/*
name 测试可枚举属性
like game
*/
// 可以看到属性定义 enumerable: true 才会被 for...in遍历
4. 继承的可枚举属性
var obj = {
name: '测试是否会遍历原型上的属性',
}
var triangle = { a: 1, b: 2, c: 3 }
function Person() {
this.color = 'red'
}
Person.prototype = triangle
var obj = new Person()
for (var key in obj) {
console.log(key, obj[key])
}
/*
color red
a 1
b 2
c 3
*/
/* 正是因为 for...in 会遍历对象原型链上可枚举的属性,所以一般使用for...in的时候会结合hasOwnProperty方法,确保读取到的属性是当前对象上的 */
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
console.log(key, obj[key])
}
}
/*
color red
*/
// ps 原型链上的可枚举属性都会被遍历
总结
写了几个 for...in 的验证案例,对 for...in 有一个初步的了解。
- 建议应用场景:
- 需要遍历对象上的属性的时候;
- ps 不太建议遍历数组
- 其次需要注意的点:
- 迭代是任意顺序的
- 属性需要可枚举
- 注意 Symbol
- 注意原型链上的可枚举属性
- 相关的方法
-
Object.defineProperty()
-
enumerable
-
Object.prototype.propertyIsEnumerable()