1. 扩展运算符

…表示,将一个数组转为用逗号分隔的参数序列,如下:

console.log(...[1,2,3]) // 1 2 3

console.log(1, ...[2,3,4], 5) // 1 2 3 4 5

[...document.querySelectorAll('div')] // [<div>, <div>, <div>]


function add(x, y){
    return x + y
}
const n = [3, 5]
add(...n) // 8
扩展运算符可以和正常函数结合使用,如下:
function f(a,b,c,d,e){
    console.log(a,b,c,d,e)
}
const age = [0,1]

f(-1,...age,2,...[3]) // -1 0 1 2 3
扩展运算符后面也可以是表达式,如下:
const x = 10
const arr = [
    ...(x > 0 ? ['a'] : []), 'b',
]

arr // ['a', 'b']
重要:如果扩展运算符后面是一个空数组,将不会有任何效果。另外只有在函数调用的时候扩展函数在放在圆括号之内,其他的则会报错。
替代函数的apply方法

扩展函数可以展开数组,所以将不需要apply方法来将数组转换为函数的参数。

function f(x, y, z){
    console.log(x, y, z)
}

var a = [1,2,4]

// ES5 
f.apply(null, args)

// ES6
f(...a)


// Math.max方法

//ES5
Math.max.apply(null, [14, 3, 99])

//ES6
Math.max(...[12, 4, 55])

//等同于
Math.max(12, 4, 55)

// push方法的应用

var a = [0,1,2]
var b = [3,4,5]

//ES5
Array.prototype.push.apply(a,b) // 0,1,2,3,4,5

//ES6
a.push(...b)
扩展运算符的应用
  1. 复制数组

    因为数组是复合的数据类型,直接的复制只是复制数组在堆内存中的指针地址
    
    const a1 = [1,2]
    const a2 = a1
    
    a2[0] = 3
    a1 // [3,2]
    
    // ES5 通过变通方法来复制
    const a1 = [1,2]
    const a2 = a1.concat()
    
    a2[0] = 23
    a1 // [1,2]
    
    // ES6写法
    const b1 = [1,3]
    const b2 = [...b1] or [...b2] = b1
    
  2. 合并数组

    const a1 = ['b', 'c']
    const a2 = ['d']
    const a3 = ['x', 'y']
    
    // ES5中合并数组
    a1.concat(a2, a3)
    
    // ES6中合并数组
    [...a1, ...a2, ...a3]
    
    //以上两种都是浅拷贝,修改原数组和同步新数组
    
  3. 与解构赋值一起使用,扩展只能放在最后一位,不然会报错

    // ES5
    a = list[0], rest = list.slice(1)
    
    // ES6
    [a,...rest] = list
    
    // 其他
    const [a,...c] = [1,2,4,5,4,6] // a 1   c 2,4,5,4,6
    const [a,...c] = [] // a undefined   c []
    const [a,...c] = ['a'] // a 'a'   c []  
    
  4. 字符串,将字符串转换为数组

    [...'hello'] // [h,e,l,l,0]
    
  5. 实现了Iterator接口的对象

    任何定义了遍历器接口对象,都可以用扩展运算符转为真正的数组
    
    let nodelist = document.querySelectorAll('div')
    let array = [...nodelist]
    // querySelectorAll 返回的是一个类数组,通过扩展运算符
    将其转换为一个真正的数组
    
  6. Map 和 Set 解构,Generator函数

    扩展运算符调用的是数据解构的Iterator接口,只要有Iterator接口的
    对象,都可以使用扩展运算符
    
    // Map
    let map = new Map([
        [1, 'a'],
        [2, 'b'],
        [3, 'c'],
    ])
    let arr = [...map.keys()] // 1, 2, 3
    let arr = [...map.values()] // 'a', 'b', 'c'
    
    //Generator函数
    const go = function*(){
        yield 1;
        yield 2;
        yield 3;
    }
    [...go()] // [1, 2, 3]
    

2. Array.from()

Array.from 方法用于将两类对象转为真正的数组。1、类似数组对象 和 可遍历的对象(包裹Set和Map),如下:

let arrLike = {
    '0': 'a',
    '1': 'b',
    '2': 'c',
    length: 3
}

// ES5 
var a1 = [].slice.call(arrLike)

// ES6
var a2 = Array.from(arrLike)

在实际中,像获取dom后返回的Nodelist集合,以及函数内部的arguments对象就是类数组,通过 Array.from将它们转换为真正的数组。

// NodeList 对象
let ps = document.querySelectorAll('p')
Array.from(ps).filter(p => {
    return p.textContent.length > 100
})

// arguments 对象
function foo(){
    var arg = Array.from(arguments)
}

// 只要部署了Iterator接口的数据解构,Array.from都能将其转成数组
Array.from('hello') // ['h', 'e', 'l', 'l', 'o']

let nl = new Set([1, 2])
Array.from(nl) // [1, 2]

// 如果是真数组则返回一样的
Array.from([1, 2, 3]) // [1, 2, 3]

… 扩展运算符也可以将某些类数组转换为数组,如arguments和NodeList集合

拥有lenght属性的对象都可以通过Array.from转换为数组,而扩展运算符则不行。

Array.from({lenght:3}) // [undefined, undefined, undefined]

对于低版本的浏览器,可以通过 Array.prototype.slice 方法替代

Array.from 还可以接受第二个参数如同map一样,用来对每个元素进行操作,并将处理后的值放入返回的数组中。

const arrlike = new Set([1,2,3])
Array.from(arrlike, x => x * x)   // =
Array.from(arrlike).map(x => x * x)   // [1, 4, 9]

//注意: 如果map中用到了this,可以传入Array.from
的第三个参数,用来绑定this

Array.from 可以将各种值转换为真正的数组,并且还提供map相关功能,这样代表如果有个原始数据结构,可以先将他转换为数组,然后使用数组相关的方法。

3. Array.of()

用于将一组值,转换为数组。主要用来弥补Array函数因为参数个数不同而导致的差异

Array.of(3,11,6) // [3, 11, 6]
Array.of(3) // [3]
Array.of(4).length // 1

4. 数组的实例 copyWithin()

将当前数组中指定位置的元素复制到另外一个位置,并且会覆盖那个位置的原有元素,会修改当前数组

// 有三个参数
1. target(必须):从该位置开始替换数据,如果是负值,则倒数
2. start(可选):从该位置读取数据,默认0,负值同上
3. end(可选):到这个位置停止读取数据,默认等于数组长度,负值同上


let p = [1,2,3,4,5,6,7]
p.copyWithin(0,5,7)
[6, 7, 3, 4, 5, 6, 7]

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

find 用来找出数组中符合条件的成员,它的参数是一个回调函数,找到一个返回值为true的返回,如果没有则返回undefined

let s = [1,2,3,4,5,6]

s.find(x => x > 4)
// 5

find 方法的回调函数有三个参数

    value // 当前值
    index // 当前的位置
    arr // 原数组

findIndex 同find方法类似,只不过都不符合返回的是 -1,而且符合是返回符合条件值的位置而不是值。

let s = [1,2,3,4,5,6]

s.find(x => x > 4)
// 4

find 和 findIndex 都可以接受第二个参数

function o(p){
    return p > this.age
}

const u = {name: 'cx', age: 11}
const y = [8,11,22,2,4]

y.find(o, u) // 22  返回的值
y.findIndex(o, u) // 2  返回值的位置

6. 数组实例的 fill()

通过给定值,填充一个数组

let sz = [1,2,3,4,5,6]

sz.fill(1) // [1,1,1,1,1,1]

sz.fill(1,0,3) 
// 接受三个参数,第一个为填充值,第二个为起始位置,第三个为截至位置

sz.fill(1,3)
// 如果省略最后一个参数,则默认从起始位置到数组默认长度结束

7. 数组实例的 entries(), keys(), values()

三种方法主要用于遍历数组,可以用 for…of…进行遍历,keys()对应键名,values对应键值,entries()对键值对的遍历

let bo = ['a', 'c']

for(let r of bo.keys()){
    console.log(r) // 0 1
}
// 0 1

for(let n of bo.values()){
    console.log(n) 
}
// a c

for(let s of bo.entries()){
    console.log(s)
}
// [0, "a"]
// [1, "c"]

8. 数组实例的 includes()

用来表示某个数组是否包含给定的值,返回一个布尔值

let i = ['a',1,2,3]

i.includes()  // false
i.includes(1) // true
i.includes(10) // false

indexOf 和includes 的区别

indexOf // 不够语义化,它的作用是找到参数出现的第一个位置,
所以要比较是否为 -1,另外由于 内部使用的是 ===  则导致NaN
的误判。

// [NaN].indexOf(NaN) // -1

includes // 使用的是不一样的算法,则不会有这个问题

// [NaN].includes(NaN) // true

Map 和 Set 的has 方法和includes的区别

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

9. 数组的实例 flat(), flatMap()

flat() 将嵌套的二维数组变成一维数组,如果需要拉平多维数组,则flat(多维数量) 或者使用 Infinity 直接转为一维数组

let rw = [1,2,3,[4,5,6],7]
rw.flat()  // [1, 2, 3, 4, 5, 6, 7]

let dw =  [1,2,3,[4,5,6,[7,8],[2,['a','b'],4,5]],[5,6,]]
dw.flat(3) // [1, 2, 3, 4, 5, 6, 7, 8, 2, "a", "b", 4, 5, 5, 6]

// 如果你不知道是多少层嵌套而都想转成一维,可以使用 Infinity
dw.flat(Infinity) 
// [1, 2, 3, 4, 5, 6, 7, 8, 2, "a", "b", 4, 5, 5, 6]

flatMap() 对数组执行map,然后对返回值组成的数组 执行flat,不会改变原数组。flatMap只能展开一层数组。

let mp = [2,3,4,5]

mp.flatMap((item) => [item, item* 2])
// [2, 4, 3, 6, 4, 8, 5, 10]
====
mp.map((item) => [item, item*2])
// [[2,4],[3,6],[4,8],[5,10]]
mp.flat()
// [2, 4, 3, 6, 4, 8, 5, 10]    

10. 数组的空位(避免出现空位)

数组的空位指的是该数组中某一个位置没有任何值。另外空位不是undefined,如果一个位置的值是undefined,那么这个位置还是有值的。

Array(3) // [, , ,]

ES5中大多数情况中对待空位都是会忽略

- forEach(), filter(), reduce(), every() 和 some() 都会跳过空位
- map() 跳过但保留这个值
- join() 和 toString() 中 空位 === undefined,而 undefined和null会被处理成空字符串

ES6 中 空位则转换为undefined

- Array.from([1,,2]) // [1, undefined, 2]
- [...['a',,'b']]    // [ "a", undefined, "b" ]

entries()
keys()
values()
find()
findIndex()  // 都会将空位处理成undefined。