扩展运算符
含意
扩展运算符(spread)是三个点(...)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。
console.log(...[1,2,3])
console.log(1,2,3)
const f1 = () => {
return ['f','g']
}
let x = 1
let arr = [
'a',
...['b', 'c'], // 数组结构
...(x > 0 ? ['d', 'e'] : []), // 表达式
...f1(), // 函数的返回值
...[], // 空数组什么也不会做
]
[...{a:1}] // 报错
应用
1.替代函数的 apply 方法
es5 里面要让数组成员成为函数的参数 需要使用 apply
const sum = (...params) => {
let total = 0
for (let item of params) {
total += item
}
return total
}
let arr = [1,2,3]
sum.apply(null, arr)
sum(...arr)
sum(1,2,3)
2.复制数组
数组是复合的数据类型,直接复制的话,只是复制了指向底层数据结构的指针,而不是克隆一个全新的数组。
const arr1 = [1, 2];
const arr2 = arr1; // 复制的只是内存地址,地址的数据变了就变了。
const arr3 = [...arr1]; // 复制的地址内成员的值,在组成数组。
arr1[0] = 2;
arr2 // [2, 2]
arr3 // [1, 2]
// 还可以写成这样
const [...arr4] = arr1 // 结合了 扩展运算符和结构赋值的知识
3.合并数组
let arr1 = [1,2]
let arr2 = [2,2]
arr1.concat(arr2)
[...arr1,...arr2]
4.字符串转数组
可以正确的拆分Unicode为四个字节的字符,并正确的获取长度
[...'hello']
'hello'.split('')
// 字符Unicode 为四个字节时
[...'x\uD83D\uDE80y']
'x\uD83D\uDE80y'.split('')
'x\uD83D\uDE80y'.length // 4
[...'x\uD83D\uDE80y'].length // 3
将带有Iterator 接口 的对象转换成数组
可以将Map 和 Set 结构,Generator 函数等转换成数组,也可以将数组转换成另一数组。
[...document.querySelectorAll('div')]
let arrayLike = {
'0': 'a',
'1': 'b',
length: 2
}
[...arrayLike] // Uncaught SyntaxError: Unexpected token ...
{...arrayLike}
就算是长得像数组的对象只要没得有 Iterator 接口,都不可通过扩展运算符转换成数值(但可以转换成对象)。
Array.from()
Array.from方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map),还有字符串。
在转换数值方面与扩展运算符很相似。一下功能会达到一样的效果。
- 复制数组
- 字符串转数组
- 将带有Iterator 接口 的对象转换成数组
有一点比扩展字符串更好用。能将长得像数组的对象转换成真正的数组。
let arrayLike = {
'0': 'a',
'1': 'b',
length: 2
}
Array.from(arrayLike)
Array.from 将长得像数组的对象转换成的数组的注意以下两点:
- 转换成的数值长度由
length属性觉定 - 对象的
key值对应数值所在的位置。所以 应该是 0 <= key < length 内的整数。可以是字符串。
let obj1 = {
'1': 'a',
'2': 'b',
length: 3,
}
Array.from(obj1) // [undefined, "a", "b", ]
let obj2 = {
'a': 'x',
'0': 'a',
'2': 'b',
'1': 'c',
length: 2,
}
Array.from(obj2)
Array.from还可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组。
Array.from([1, 2, 3], (x) => x * x)
// [1, 4, 9]
Array.from([1, 2, 3]).map(x => x * x)
// [1, 4, 9]
Array.of()
Array.of方法用于将一组值,转换为数组。
Array.of() // []
Array.of(3) // [3]
Array.of(1, 2, 3) // [1, 2, 3]
构造函数也可以将参数变成数组,但是有缺点。
当构造函数有且只有一个参数且这个参数类型是数值时, 这个参数会被用来指定数组的长度。
Array() // []
Array(3) // [,,,]
Array(1, 2, 3) // [1, 2, 3]
Array.of基本上可以用来替代Array()或new Array(),并且不存在由于参数不同而导致的重载.
数组实例的 方法
copyWithin()
Array.prototype.copyWithin(target, start = 0, end = this.length)
修改数组将指定位置的数组成员替换成 start 到 end 之前的成员。
当start和end 为负数时表示倒数。
[0,1,2,3,4].copyWithin(0, 3, 4) // 将3号位置覆盖到0号位置
// [3, 1, 2, 3, 4]
[0,1,2,3,4].copyWithin(0, -2, -1) // -2相当于3号位,-1相当于4号位
// [3, 1, 2, 3, 4]
[0,1,2,3,4,5,6].copyWithin(1, 3, 6) // 从2号位开始依次被 4到6号位的成员替换。
// [0,3,4,5,4,5,6]
fill()
Array.prototype.fill(replace, start = 0, end = this.length)
fill方法使用给定值replace,替换掉start 到 end 之前的成员。
当start和end 为负数时表示倒数。
['a', 'b', 'c'].fill('x')
// ['x','x','x']
['a','b', 'c'].fill('x', 1, 2)
// ["a", "x", "c"]
find()
find() 的参数为一个回调函数。
在执行时遍历数组成员,当有回调函数返回值为true时,find()返回该数组成员并停止遍历。若遍历结束都没有返回true, find() 返回undefined。
主要功能用来在数组中查找符合条件的成员。
[1, 4, -5, 10].find(value => value < 0)
// -5
[1, 4, -5, 10].find((value,index,array) => {
console.log(value,index,array)
})
上面代码中,find方法的回调函数可以接受三个参数,依次为当前的值、当前的位置和原数组。
findIndex()
findIndex() 的参数为一个回调函数。
用法与find()方法非常类似,在执行时遍历数组成员,当有回调函数返回值为true时,find()返回该数组成员的位置并停止遍历。若遍历结束都没有返回true, find() 返回-1。
[1, 4, -5, 10].findIndex((value, index, arr) => value < 0)
// 2
上面代码中,findIndex方法的回调函数可以接受三个参数,依次为当前的值、当前的位置和原数组。
返回结果跟indexOf 很相似。 都是返回第一个符合条件的数组成员的位置,若没有符合条件的成员就返回-1。
但是indexOf 无法识别NaN,而findIndex 可以借助Object.is方法做到。
[NaN].indexOf(NaN)
// -1
[NaN].findIndex(value => Object.is(NaN, value)) // find() 也可以
// 0
includes()
Array.prototype.includes方法返回一个布尔值,表示某个数组是否包含给定的值。
[1, 2, 3].includes(2) // true
[1, 2, 3].includes(4) // false
[1, 2, NaN].includes(NaN) // true
用 includes() 判断数组内是否有NaN比 findIndex 更方便。
includes() 有第二个参数,表示从该位置开始搜索。如果为负数表示倒数。
[1, 2, 3].includes(3, 3); // false
[1, 2, 3].includes(3, -1); // true
entries(),keys() 和 values()
let arr = ['a', 'b']
for (let index of arr.keys()) {
console.log(index);
}
// 0
// 1
for (let item of arr.values()) {
console.log(item);
}
// 'a'
// 'b'
for (let [index, item] of arr.entries()) {
console.log(index, item);
}
// 0 "a"
// 1 "b"
// 如果不使用for...of循环,可以手动调用遍历器对象的next方法,进行遍历。
let entries = arr.entries();
console.log(entries.next().value); // [0, 'a']
console.log(entries.next().value); // [1, 'b']
数组的空位
数组的空位指,数组的某一个位置没有任何值。比如,Array构造函数返回的数组都是空位。
[, , ,]
Array(3) // [, , ,]
空位不是undefined,一个位置的值等于undefined,依然是有值的。空位是没有任何值,in运算符可以说明这一点。
let arr = [undefined, 1, ]
0 in arr // true
1 in arr // true
2 in arr // false
Array.from 和扩展运算符 可以将数组的空位,转为undefined。
Array.from(['a',,'b'])
// [ "a", undefined, "b" ]
[...['a',,'b']]
// [ "a", undefined, "b" ]
copyWithin()会连空位一起拷贝。
[,'a','b',,].copyWithin(2,0) // [,"a",,"a"]
fill()会将空位视为正常的数组位置。
new Array(3).fill('a') // ["a","a","a"]
for...of循环也会遍历空位。 但是map 遍历会跳过 空位.
let arr = [, ,]
for (let i of arr) {
console.log(1)
}
// 1
// 1
arr.map(item => {
console.log(1)
})
entries()、keys()、values()、find()和findIndex()会将空位处理成undefined。
let arr = [,'a']
// entries()
[...arr.entries()] // [[0,undefined], [1,"a"]]
// keys()
[...arr.keys()] // [0,1]
// values()
[...arr.values()] // [undefined,"a"]
// find()
arr.find(x => true) // undefined
// findIndex()
arr.findIndex(x => true) // 0
题
1.使用 Math.max 求 arr 中最大值。
let arr = [1,2,3,9,2]
2. 求 arr2 和 arr3
const arr1 = [1]
const arr2 = arr1
const arr3 = [...arr1]
arr1[0] = 2;
3.字符串 'a𠮷b' 拆分成数组后的长度。
let str = 'a𠮷b'
str.split('').length
[...str].length
4. obj 转换成数组的方式, 转换后的结果。
const obj = {
a: 1,
'0': 'xx',
1: 'yy',
length: 1,
}
5. 输出结果
Array.of(3)
new Array(3)
[0,1,2,3,4].copyWithin(1, -2, -1)
[0,1,2,3,4].fill('x', 1,3)
[1,3,11,2].find(value => value > 10)
[1,3,11,2].findIndex(value => value > 10)
6. 判断一个 数组里面是否含有 NaN
// includes findIndex() find()
7. 输出结果
'aavvbbvv'.includes('aa',0)
'aavvbbvv'.includes('bb',-4)
8. 输出结果
let arr = [undefined, 1, ]
0 in arr
1 in arr
2 in arr