ES6 Array 之遍历数组的方法

1,572 阅读1分钟

这是我参与8月更文挑战的第1天,活动详情查看:8月更文挑战

方法简洁程度break/continue 的支持备注
for用于遍历数组,遍历过程受控,可以通过 breakcontinue 实现对遍历的控制
forEachES5 新增。用于遍历数组,遍历过程不受控,会遍历完所有元素
every--ES5 新增。用于遍历数组,遍历过程受控,通过设置函数返回值的真假,实现和 breakcontinue 相同的效果
for in--ES3 中就存在了。为 object 设计的,数组属于 object,也能用,但有瑕疵。遍历出的元素的索引是 string 类型的,而不是 number 类型。for in 会把自定义属性也遍历出来。
for of--ES6 新增。用于遍历自定义的数据结构(该自定义的数据结构不是数组,也不是 object),同时也可以遍历数组。通过修改默认的遍历机制,配合 for of 的使用,使得 for of 的功能非常强大。

1. for

const arr = [1, 2, 3, 4, 5]
for (var i = 0; i < arr.length; i++) {
  console.log(arr[i])
}

/* 结果:
1
2
3
4
5
*/
const arr = [1, 2, 3, 4, 5]
for (var i = 0; i < arr.length; i++) {
  if (arr[i] === 2) {
    break // for 循环中 break 有效
  }
  console.log(arr[i])
}

/* 结果:
1
*/
const arr = [1, 2, 3, 4, 5]
for (var i = 0; i < arr.length; i++) {
  if (arr[i] === 2) {
    continue // for 循环中 continue 有效
  }
  console.log(arr[i])
}

/* 结果:
1
3
4
5
*/

2. forEach

const arr = [1, 2, 3, 4, 5]
arr.forEach(function (item) {
  console.log(item)
})

/* 结果:
1
2
3
4
5
*/
const arr = [1, 2, 3, 4, 5]
arr.forEach(function (item) {
  if (item === 2) {
    break // 报错:Unsyntactic break
  }
  console.log(item)
})
const arr = [1, 2, 3, 4, 5]
arr.forEach(function (item) {
  if (item === 2) {
    continue // 报错:Unsyntactic continue
  }
  console.log(item)
})

相比于 forforEach 的写法更加简洁,但是它不支持 breakcontinue,它所遍历的是从头到尾的每个元素。

拓展:

// 声明一个长度为 5 的数组 array
let array = Array(5)
// 给数组的所有元素赋值为 1
array.forEach(function (item) {
  item = 1
})
console.log(array)

/* 结果:
(5) [empty × 5]
*/

可见,forEach 不能给数组元素赋值。

3. every

特性:every 遍历数组时,是否继续往下遍历,取决于函数的返回值,返回值为 true 时继续遍历,返回值为 false 时结束遍历,默认的返回值为 false

const arr = [1, 2, 3, 4, 5]
arr.every(function (item) {
  console.log(item) 
  // 函数返回值默认为 false,因此遍历出第一个元素后就结束遍历
})

/* 结果:
1
*/
const arr = [1, 2, 3, 4, 5]
arr.every(function (item) {
  console.log(item)
  return true // 函数返回值为 true,表示继续遍历
})

/* 结果:
1
2
3
4
5
*/

上面代码块中函数返回 true 时,every 也能遍历所有元素了,看上去和 forEach 的行为一样。你可能会问,既然在这个时候 everyforEach 的行为很像了,那为什么还要新增 every 这个 API 呢?因为我们上面说过,forEach 有弊端,forEach 是不受控的,如果你用 forEach,它必须从头遍历到尾,它不支持 breakcontinue,而 every 虽然也不支持 breakcontinue,但 every 中可以实现和 breakcontinue 相同的效果,如何实现呢?其实,every 能不能向下遍历取决于函数的返回值,想要达到break的效果,可以使用return false,想要达到continue的效果,可以使用return true,所以说 every 是受控的。

const arr = [1, 2, 3, 4, 5]
arr.every(function (item) {
  if (item === 2) {
	return false // 结束函数的执行,不再继续遍历,相当于实现了 break 的效果
  }
  console.log(item)
  return true
})

/* 结果:
1
*/
const arr = [1, 2, 3, 4, 5]
arr.every(function (item) {
  if (item === 2) {
    // 不做处理,相当于实现了 continue 的效果
  } else {
    console.log(item)
  }
  return true
})

/* 结果:
1
3
4
5
*/

4. for in

for in 是为可遍历的 object 做遍历的,而不是为数组,只是数组也属于 object,并且数组是可遍历的,所以也能用 for in 遍历,但是用 for in 遍历数组会有瑕疵。

const arr = [1, 2, 3, 4, 5]
for (var index in arr) {
  console.log(index, arr[index])
}

/* 结果:
0 1
1 2
2 3
3 4
4 5
*/
const arr = [1, 2, 3, 4, 5]
arr.pro = 8 // 为 arr 数组添加属性 pro(arr 是数组,数组是对象,对象上可以挂属性)
for (var index in arr) { 
  console.log(index, arr[index])
}

/* 结果:
0 1
1 2
2 3
3 4
4 5
pro 8
*/

可见,数组的索引不一定是数字,也可以是字符串。用 for in 遍历数组,如果数组上挂载了属性,也会被遍历出来,导致和我们的预期不同,这就是用 for in 遍历数组的瑕疵。

const arr = [1, 2, 3, 4, 5]
arr.pro = 8
for (var index in arr) { // 使用 for in 遍历,元素的索引是 string 类型的,而不是 number 类型。即这里的 index 是字符串类型
  if (index == 2) { // 左边 index 是 string 类型,右边 2 是 number 类型(注意:== 只比较值,不比较类型;而 === 既比较类型,也比较值,只要类型不同就返回 false)
    break // for in 中支持 break
  }
  console.log(index, arr[index])
}

/* 结果:
0 1
1 2
*/
const arr = [1, 2, 3, 4, 5]
arr.pro = 8
for (var index in arr) {
  if (index == 2) {
    continue // for in 中支持 continue
  }
  console.log(index, arr[index])
}

/* 结果:
0 1
1 2
3 4
4 5
pro 8
*/

上面的 if 条件判断中,如果想使用 ===,可以将 index == 2 换成 index * 1 === 2 或者 +index === 2 或者 index === '2'

字符串中只有数字时,可以通过乘 1 或在字符串前加个加号将字符串转换为 number 类型:

var test = '00023' // 字符串中只有数字
var test1 = test * 1 // 乘以 1 转换成 number 类型
var test2 = +test // 前面加个加号转换成 number 类型
console.log(test, typeof (test)) // 00023 string
console.log(test1, typeof (test1)) // 23 "number"
console.log(test2, typeof (test2)) // 23 "number"

5. for of

for of 用于遍历自定义的数据结构(该自定义的数据结构不是数组,也不是 object),同时也可以遍历数组。

5.1 遍历数组

const arr = [1, 2, 3, 4, 5]
for (let item of arr) {
  console.log(item)
}

/* 结果:
1
2
3
4
5
*/

5.2 遍历自定义的数据结构

// 假设有 A、B、C 三类商品,每类商品下有不同价格的商品,现就价格进行如下定义:
const Price = {
  A: [2.3, 1.5, 4.5],
  B: [3, 5],
  C: [0.8, 0.5, 1.2]
}

如果想要找出每类商品中的最低价,该怎么实现呢?

我们先用 for in 遍历

for (let key in Price) {
  console.log(key, Price[key])
}

/* 结果:
A (3) [2.3, 1.5, 4.5]
B (2) [3, 5]
C (3) [0.8, 0.5, 1.2]
*/

如果想要直接遍历出各类商品中的最低价,for in 无法实现,需要再做排序等其它操作。

我们再用 for of 遍历

for (const [key, value] of Object.entries(Price)) {
  console.log(key, value);
  let min = value[0];
  for (const p of value) {
    if (min > p) {
      min = p;
    }
  }
  console.log(`${key} 类商品的最低价为 ${min} 元`);
}

/* 结果:
A (3) [2.3, 1.5, 4.5]
A 类商品的最低价为 1.5 元
B (2) [3, 5]
B 类商品的最低价为 3 元
C (3) [0.8, 0.5, 1.2]
C 类商品的最低价为 0.5 元
*/