迭代对象
for...in
for...in 用于对数组或者对象的属性进行循环操作。只遍历可枚举属性(包括它的原型链上的可枚举属性)
for...in 是为了遍历对象属性而构建的,不建议数组使用,数组可以使用Array.prototype.forEach() 和 for...of。
for...in 循环有三个使用注意点:
- 只能迭代对象所有可迭代的属性,跳过不可迭代属性;
- 不仅迭代对象自身的属性,还迭代继承的属性。
for...in不可以终止循环
可枚举性
对象都继承了 toString 属性,但是 for...in 不会迭代到这个属性。为什么呢?
var obj = {}
obj.a = 'AAA'
obj['b'] = 'BBB'
'toString' in obj // true 证明 toString属性存在
for(var key in obj) {
console.log('键名:'+ key) // 输出结果中没有 toString
}
在对象的属性描述对象中存在一个 enumerable 属性,实际上引入 enumerable 最初的目的就是让某些属性可以规避掉 for...in 操作,不然所有内部属性和方法都会被迭代到。比如,对象原型的toString 方法以及数组的 length 属性,就通过“可枚举性”避免被迭代到。
使用 for...in 实现只迭代自身属性
for(var key in obj) {
if(obj.hasOwnProperty(key)) {
console.log('键名:'+ key)
}
}
Object.keys 和 Object.values
Object.keys() 返回一个由给定对象的自身可枚举属性组成的数组。
var obj = {
name:'lxx',
age:25,
height:1.88
}
var keyArr = Object.keys(obj)
keyArr // ['name','age','height']
Object.values() 方法返回一个给定对象自身的所有可枚举属性值的数组。
var valueArr = Object.values(obj)
valueArr // ['lxx',25,1.88]
Object.getOwnPropertyNames()
返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。
// 创建一个不可枚举属性
var obj = Object.create({},{
getFoo:{
value:function(){ return this.foo },
enumerable:false // 设置不可枚举
}
})
// 创建一个可枚举属性
obj.foo = 1
Object.getOwnPropertyNames(obj) // ['getFoo','foo']
迭代数组
forEach
对数组的每一个元素执行一次给定的函数。
var arr = [1,2,3,4]
arr.forEach(function(value, index) {
console.log(value, index)
})
// 1 0 2 1 3 2 4 3
forEach() 除了接受一个必须的回调函数参数,还接受第二个可选的上下文参数(用以改变回调函数里面的 this 指向)
for...in
👎 不推荐。和遍历对象的 for...in 是一样的。
var arr = ['a','b','c']
for(var i in arr) {
console.log(i,':',arr[i])
}
// 0:a
// 1:b
// 2:c
如何选择迭代方法?
- 对于纯对象的遍历,
for...in要厉害一些; - 对于数组的遍历,如果不需要知道索引,
for...of迭代更适合,因为可以中断; - 如果需要知道索引,则
forEach更合适; - 对于字符串、类数组、类型数组的迭代,虽然
for...in也有这方面的能力,但是for...of更占上风。
引用 各种迭代方法的比较请看 张鑫旭 文章