JavaScript中的迭代

79 阅读2分钟

迭代对象

for...in

for...in 用于对数组或者对象的属性进行循环操作。只遍历可枚举属性(包括它的原型链上的可枚举属性) for...in 是为了遍历对象属性而构建的,不建议数组使用,数组可以使用Array.prototype.forEach()for...of

for...in 循环有三个使用注意点:

  1. 只能迭代对象所有可迭代的属性,跳过不可迭代属性;
  2. 不仅迭代对象自身的属性,还迭代继承的属性。
  3. 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

如何选择迭代方法?

  1. 对于纯对象的遍历, for...in 要厉害一些;
  2. 对于数组的遍历,如果不需要知道索引,for...of 迭代更适合,因为可以中断;
  3. 如果需要知道索引,则 forEach 更合适;
  4. 对于字符串、类数组、类型数组的迭代,虽然 for...in 也有这方面的能力,但是 for...of 更占上风。

引用 各种迭代方法的比较请看 张鑫旭 文章