1. 扩展运算符
...表示,将一个数组转为用逗号分隔的参数序列,如下:
console.log(...[1,2,3]) // 1 2 3
console.log(1, ...[2,3,4], 5) // 1 2 3 4 5
[...document.querySelectorAll('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方法
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)
扩展运算符的应用
-
复制数组
因为数组是复合的数据类型,直接的复制只是复制数组在堆内存中的指针地址
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
-
合并数组
const a1 = ['b', 'c']
const a2 = ['d']
const a3 = ['x', 'y']
// ES5中合并数组
a1.concat(a2, a3)
// ES6中合并数组
[...a1, ...a2, ...a3]
//以上两种都是浅拷贝,修改原数组和同步新数组
-
与解构赋值一起使用,扩展只能放在最后一位,不然会报错
// 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 []
-
字符串,将字符串转换为数组
[...'hello'] // [h,e,l,l,0]
-
实现了Iterator接口的对象
任何定义了遍历器接口对象,都可以用扩展运算符转为真正的数组
let nodelist = document.querySelectorAll('div')
let array = [...nodelist]
// querySelectorAll 返回的是一个类数组,通过扩展运算符
将其转换为一个真正的数组
-
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。
本文系作者 @坚果大叔 原创发布在 卖坚果的怪叔叔。未经许可,禁止转载。