数组的扩展

扩展运算符

1
2
3
4
5
6
7
8
9
10
11
console.log(...[1, 2, 3]) //1 2 3
console.log(1, ...[2, 3], 4) //1 2 3 4
;[...document.querySelectorAll("div")] //[<div>, <div>, ...];

function add(x, y) {
return x + y
}
add(...[1, 2]) //3

//与表达式一同使用
const arr = [...(x > 0 ? ["a"] : []), "b"]

扩展运算符的应用

  • 替代数组的 apply 方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    function f(x, y, z) {}
    var args = [0, 1, 2]

    //ES5 写法
    f.apply(null, args)

    //ES6 写法
    f(...args)

    //用 Math.max 求数组中最大的数
    //ES5 写法
    Math.max.apply(null, [2, 33, 3])

    //ES6 写法
    Math.max(...[2, 33, 3])

    //用 push 将一个数组添加到另一个数组尾部
    var arr1 = [0, 1, 2]
    var arr2 = [3, 4, 5]

    //ES5 写法
    Array.prototype.push.apply(arr1, arr2)

    //ES6 写法
    arr1.push(...arr2)
  • 合并数组

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var arr1 = ["a"]
    var arr2 = ["b", "c"]
    var arr3 = ["d"]

    //ES5 写法
    arr1.concat(arr2, arr3)

    //ES6 写法
    ;[...arr1, ...arr2, ...arr3]
  • 与解构赋值结合

    如果将扩展运算符用于数组赋值,只能将其放在最后一位

    1
    const [first, ...middle, last] = [1, 2, 3, 4, 5]; //SyntaxError: Rest element must be last element
  • 函数的返回值

  • 字符串

  • 实现了 Iterator 接口的对象

  • Map 和 Set 解构、Generator 函数

Array.from()

Array.from()将两类对象转换成真正的数组:

  • array-like object
  • iterable object
1
2
3
4
5
6
7
8
9
10
11
12
let arrayLike = {
0: "a",
1: "b",
2: "c",
length: 3,
}

//ES5 写法
var arr = [].slice.call(arrayLike)

//ES6 写法
let arr = Array.from(arrayLike)

DOM 操作返回的 NodeList 集合,以及函数内部的 arguments 对象,Array.from()都可以将他们转换成真正的数组

1
2
//String 有 Iterator 接口
Array.from("hello") //['h', 'e', 'l', 'l', 'o']

Array.from()还可以接受第二个参数,类似于数组的 map 方法,对每个元素进行处理,将处理后的值放入返回的数组。

1
2
3
4
5
Array.from(arrayLike, x => x _ x);
//等同于
Array.from(arrayLike).map(x => x _ x);

Array.from({ length : 2 }, () => 'test'); //['test', 'test']

另一个用途是将字符串转为数组,然后返回长度,可以正确处理 Unicode 字符

1
2
3
function countSymbols(string) {
return Array.from(string).length
}

Array.of()

Array.of 用于将一组值转换为数组。

1
2
3
Array.of(1, 2, 3) //[1, 2, 3]
Array.of() //[]
Array.of(undefined) //[undefined]

模拟实现:

1
2
3
function ArrayOf() {
return [].slice.call(arguments)
}

数组实例的 copyWithin()

在当前数组内将指定位置的成员复制到其他位置,然后返回当前数组。接受三个参数:

1
Array.prototype.copyWithin(target, (start = 0), (end = this.length))
  • target(必选):从该位置开始替换数据
  • start(可选):从该位置开始读取数据,默认为 0。如果为负数,表示倒数。
  • end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负数,表示倒数。

这三个参数会自动转为数值

1
2
3
//从 0 位置开始,将 3 开始到 this.length 的位置的数据填入
;[1, 2, 3, 4, 5].copyWithin(0, 3) //[4, 5, 3, 4, 5];
;[1, 2, 3, 4, 5].copyWithin(0, 2) //[3, 4, 5, 4, 5];

数组实例的 find()和 findIndex()

find 用于找出第一个符合条件的数组成员,参数是一个回调函数,如果没有符合的成员,返回 undefined。

1
;[1, 3, -5, 3, 2].find((n) => n < 0) //-5

findIndex 方法与 find()类似,没有符合的成员时返回-1。
这两个方法都可以接受第二个参数,用来绑定回调函数的 this 对象,这两个函数都能发现 NaN,弥补了 IndexOf 的不足。

1
2
;[NaN].indexOf(NaN) //-1
;[NaN].findIndex((y) => Object.is(NaN, y)) //0

数组实例的 fill()

与 copyWithin 一样,接受三个参数:

  • value:用于填充的值
  • start:起始位置
  • end:结束位置
1
;["a", "b", "c"].fill("7", 0, 1) //['7', 'b', 'c']

数组实例的 entries()、keys()和 values()

ES6 提供了 3 个新方法用于遍历数组,他们都返回一个 Generator 对象,可用 for…of 遍历。
唯一的区别在于 keys()是对键名遍历,values()是对键值遍历,entries()是对键值对遍历。

数组实例的 includes()

Array.prototype.includes 方法返回一个布尔值,表示某个数组是否包含给定的值,与 string 的 includes 方法类似。ES2016 引入了该方法。
Map 和 Set 有 has 方法,需与 includes 区分

  • Map 的 has 方法是查找键名的
  • Set 的 has 方法是查找键值的

数组的空位

数组的空位指数组的某一个位置没有任何值。比如 Array 构造函数返回的数组都是空位。

1
Array(3) //[, , ,]

空位不是 undefined

1
2
0 in [undefined, undefined, undefined] //0 号位置有值
0 in [, , ,] //0 号位没值

ES5 大多数情况下会忽略空位:

  • forEach()、filter()、every()和 some()都会跳过空位
  • map()会跳过空位,但会保留这个值
  • join()和 toString()会将空位视为 undefined,undefined 和 null 会被处理成空字符串

ES6 将空位转为 undefined
由于空位的规则非常不统一,所以应避免出现空位