对象/数组遍历方法总结

748 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情

对象遍历

ES6 一共有 5 种方法可以遍历对象的属性。

(1)for...in

for...in循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。

示例:

const obj = {10:10, b:'bb', 2:2, a:'aa'}
for(let key in obj){
    console.log(key, obj[key])
}
// 2 2  10 1  b bb  a aa

(2)Object.keys(obj)

Object.keys返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。

const obj = {10:10, b:'bb', 2:2, a:'aa'}
console.log(Object.keys(obj))
// ["2", "10", "b", "a"]

(3)Object.entries()

Object.entries()方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。

const obj = { foo: 'bar', baz: 42 };
Object.entries(obj)
// [ ["foo", "bar"], ["baz", 42] ]

(4)Object.getOwnPropertyNames(obj)

Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。

const obj = {10:1, b:'bb', 2:2, a:'aa'}
console.log(Object.getOwnPropertyNames(obj))
// ["2", "10", "a", "b"]

(5)Object.getOwnPropertySymbols(obj)

Object.getOwnPropertySymbols返回一个数组,包含对象自身的所有 Symbol 属性的键名。

const obj = {10:1, b:'bb', [Symbol('1')]: 1}
console.log(Object.getOwnPropertySymbols(obj))
// [Symbol(1)]

(6)Reflect.ownKeys(obj)

Reflect.ownKeys返回一个数组,包含对象自身的(不含继承的)所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。

以上的 5 种方法遍历对象的键名,都遵守同样的属性遍历的次序规则。

  • 首先遍历所有数值键,按照数值升序排列。
  • 其次遍历所有字符串键,按照加入时间升序排列。
  • 最后遍历所有 Symbol 键,按照加入时间升序排列。
Reflect.ownKeys({ [Symbol()]:0, b:0, 10:0, 2:0, a:0 })
// ['2', '10', 'b', 'a', Symbol()]

上面代码中,Reflect.ownKeys方法返回一个数组,包含了参数对象的所有属性。这个数组的属性次序是这样的,首先是数值属性2和10,其次是字符串属性b和a,最后是 Symbol 属性。

数组遍历

(1)for循环

for(let i=0; i< arr.length; i++){
    // ...
}

在这种循环方式中,循环每进行一次,就要检查一下数组长度。读取属性(数组长度)要比读局部变量慢,尤其是当 array 里存放的都是 DOM 元素,因为每次读取都会扫描一遍页面上的选择器相关元素,速度会大大降低。所以可以将arr.length存到局部变量中进行优化:

let len = arr.length
for(let i=0; i< len; i++){
    // ...
}

(2)for ... in循环

for(let i in arr){
    console.log(i, arr[i])
}

for-in需要分析出array的每个属性,这个操作性能开销很大。用在 key 已知的数组上是非常不划算的。所以尽量不要用for-in,除非你不清楚要处理哪些属性,例如 JSON对象这样的情况

(3)for ... of 循环

for of只能遍历数组不能遍历对象

for(let val in arr){
    console.log(val)
}

(4)Array.forEach(callback)

forEach() 方法为每个数组元素调用一次函数(回调函数)。回调可以接收3个参数:元素,索引,数组本身

示例:

const arr = ['a', 2, 10, 'b']
arr.forEach(function(item, index, ar){
    console.log(item, index, ar)
})
// a 0  ["a", 2, 10, "b"]
// 2 1  ["a", 2, 10, "b"]
// 10 2  ["a", 2, 10, "b"]
// b 3  ["a", 2, 10, "b"]

效率速度:for > for-of > forEach > for-in

(5)Array.map(callback)

map()可以通过return返回一个新数组,不改变原来数组,回调可以接收3个参数:元素,索引,数组本身

const arr = ['a', 2, 10, 'b']
const newArr = arr.map(function(item, index, ar){
    return item + '1'
})
console.log(arr, newArr)
// arr: ["a", 2, 10, "b"]
// newArr: ["a1", "21", "101", "b1"]

(6)Array.filter()

filter() 方法创建一个包含通过测试的数组元素的新数组。常做条件过滤使用。

const arr = [8, 2, 10, 4]
const newArr = arr.filter(function(item, index, ar){
    return item > 5
})
console.log(newArr)
// [8, 10]

(7)Array.reduce()

reduce() 方法在每个数组元素上运行函数,以生成(减少它)单个值。reduce() 方法不会减少原始数组。此函数回调接受 4 个参数:总数(初始值/先前返回的值)、当前元素、索引、数组本身

var arr = [45, 4, 9, 16, 25];
var sum = arr.reduce(myFunction);
function myFunction(total, value, index, array) {
  return total + value;
}
console.log(sum)  // 99
console.log(arr)  // [45, 4, 9, 16, 25]

(8)Array.reduceRight()

reduceRightreduce用法一样,唯一区别是reduce遍历是从左到右遍历元素。reduceRight是从右到左。

(9)Array.every()

every() 方法检查所有数组每个元素值是否通过测试/条件判断。返回值为true或false

var arr = [45, 4, 9, 16, 25];
var res = arr.every(function (value, index, array) {
  return value > 18;
});
console.log(res)  // false
var arr1 = ['abc', 'apple', 'aha'];
var res1 = arr.every(function (item, index, array) {
  return item.indexOf('a')>-1;
});
console.log(res1)  // true

(10)Array.some()

some() 方法检查所有数组是否有元素值通过测试/条件判断。有一个元素满足条件则返回值为true。每个值都不满足则为false

var arr = [45, 4, 9, 16, 25];
var res = arr.some(function (value, index, array) {
  return value > 18;
});
console.log(res)  // true