擴(kuò)展運(yùn)算符(...)
基本用法
- 該運(yùn)算符作用正好與rest參數(shù)作用相反,用于展開(kāi)數(shù)組為參數(shù)序列,用逗號(hào)分割。
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 push(array, ...items) {
array.push(...items);
}
function add(x, y) {
return x + y;
}
const numbers = [4, 38];
add(...numbers) // 42
應(yīng)用
- 復(fù)制數(shù)組,數(shù)組作為一個(gè)復(fù)合型的數(shù)據(jù)結(jié)構(gòu),直接復(fù)制的話只是復(fù)制了指向數(shù)組的指針
//錯(cuò)誤
const a1 = [1, 2];
const a2 = a1;
a2[0] = 2;
a1 // [2, 2]
//正確
const a1 = [1, 2];
// 寫法一
const a2 = [...a1];
// 寫法二
const [...a2] = a1;
- 合并數(shù)組
var arr1 = ['a', 'b'];
var arr2 = ['c'];
var arr3 = ['d', 'e'];
[...arr1, ...arr2, ...arr3]
- 與解構(gòu)賦值結(jié)合起來(lái),用于生成新數(shù)組,只能將擴(kuò)展運(yùn)算符放在最后一位
const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest // [2, 3, 4, 5]
const [first, ...rest] = [];
first // undefined
rest // []
const [first, ...rest] = ["foo"];
first // "foo"
rest // []
- 轉(zhuǎn)變字符串為數(shù)組,可以正確識(shí)別四個(gè)字節(jié)的字符串
let str = 'x\uD83D\uDE80y';
str.split('').reverse().join('')
// 'y\uDE80\uD83Dx'
[...str].reverse().join('')
// 'y\uD83D\uDE80x'
- 將實(shí)現(xiàn)了 Iterator 接口的對(duì)象轉(zhuǎn)化為數(shù)組
let nodeList = document.querySelectorAll('div');
let array = [...nodeList];
- nodeList是一個(gè)類似數(shù)組的對(duì)象,可以將其轉(zhuǎn)化為真正的數(shù)組
- 對(duì)于那些沒(méi)有部署 Iterator 接口的類似數(shù)組的對(duì)象,擴(kuò)展運(yùn)算符就無(wú)法將其轉(zhuǎn)為真正的數(shù)組,可以使用Array.from
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
// TypeError: Cannot spread non-iterable object.
let arr = [...arrayLike];
- Map 和 Set 結(jié)構(gòu),Generator 函數(shù)
- 這些結(jié)構(gòu)都可以轉(zhuǎn)化為數(shù)組,擴(kuò)展運(yùn)算符內(nèi)部調(diào)用的是數(shù)據(jù)結(jié)構(gòu)的 Iterator 接口,因此只要具有 Iterator 接口的對(duì)象,都可以使用擴(kuò)展運(yùn)算符
方法
Array.from()
- Array.from方法用于將兩類對(duì)象轉(zhuǎn)為真正的數(shù)組:類似數(shù)組的對(duì)象(array-like object)和可遍歷(iterable)的對(duì)象(包括ES6新增的數(shù)據(jù)結(jié)構(gòu)Set和Map)。
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
- 值得注意的是擴(kuò)展運(yùn)算符也可以將其他結(jié)構(gòu)轉(zhuǎn)化為數(shù)組,但擴(kuò)展運(yùn)算符是調(diào)用遍歷器接口做到的,而Array.from()是通過(guò)一個(gè)對(duì)象的length屬性,換句話說(shuō)只要一個(gè)對(duì)象有l(wèi)ength屬性就可以將他看做類數(shù)組對(duì)象
Array.from({ length: 3 });
// [ undefined, undefined, undefined ]
- 如果參數(shù)是一個(gè)數(shù)組,則返回原數(shù)組。
- 該方法還可以接受第二個(gè)參數(shù),對(duì)新數(shù)組中的每個(gè)元素進(jìn)行操作,類似map方法
Array.from([1, 2, 3], (x) => x * x)
// [1, 4, 9]
Array.of()
- 該函數(shù)的出現(xiàn)主要是為了彌補(bǔ)Array構(gòu)造函數(shù)的不足,Array的構(gòu)造函數(shù)會(huì)因?yàn)閰?shù)的數(shù)量不同而產(chǎn)生一些不一致的問(wèn)題,如下
Array() // []
Array(3) // [, , ,]
Array(3, 11, 8) // [3, 11, 8]
- 當(dāng)沒(méi)有參數(shù)是,返回一個(gè)空數(shù)組,當(dāng)有一個(gè)參數(shù)時(shí),將該參數(shù)作為數(shù)組長(zhǎng)度,當(dāng)參數(shù)長(zhǎng)度大于倆個(gè)時(shí),才以這些參數(shù)作為元素構(gòu)成數(shù)組。
數(shù)組實(shí)例的 copyWithin()
- 該方法用于改變數(shù)組內(nèi)部的值通過(guò)賦值數(shù)組內(nèi)部其他值來(lái)覆蓋需要改變的值,該方法接受三個(gè)參數(shù)
- target(必需):從該位置開(kāi)始替換數(shù)據(jù)。
- start(可選):從該位置開(kāi)始讀取數(shù)據(jù),默認(rèn)為0。如果為負(fù)值,表示倒數(shù)。
- end(可選):到該位置前停止讀取數(shù)據(jù),默認(rèn)等于數(shù)組長(zhǎng)度。如果為負(fù)值,表示倒數(shù)。
// 將3號(hào)位復(fù)制到0號(hào)位
[1, 2, 3, 4, 5].copyWithin(0, 3, 4)
// [4, 2, 3, 4, 5]
// -2相當(dāng)于3號(hào)位,-1相當(dāng)于4號(hào)位
[1, 2, 3, 4, 5].copyWithin(0, -2, -1)
// [4, 2, 3, 4, 5]
// 將3號(hào)位復(fù)制到0號(hào)位
[].copyWithin.call({length: 5, 3: 1}, 0, 3)
// {0: 1, 3: 1, length: 5}
// 將2號(hào)位到數(shù)組結(jié)束,復(fù)制到0號(hào)位
let i32a = new Int32Array([1, 2, 3, 4, 5]);
i32a.copyWithin(0, 2);
// Int32Array [3, 4, 5, 4, 5]
數(shù)組實(shí)例的 find() 和 findIndex()
- find方法用于找出數(shù)組內(nèi)符合某個(gè)條件的值,參數(shù)為一回調(diào)函數(shù),返回true時(shí)表示找到,找到返回該值,找不到返回undefined
[1, 4, -5, 10].find((n) => n < 0)
// -5
- findindex方法與上類似,不同的是返回下標(biāo),若未找到返回-1
[1, 5, 10, 15].findIndex(function(value, index, arr) {
return value > 9;
}) // 2
數(shù)組實(shí)例的fill()
- 該方法使用指定值填充數(shù)組,可用于數(shù)組的初始化
['a', 'b', 'c'].fill(7)
// [7, 7, 7]
new Array(3).fill(7)
// [7, 7, 7]
- 該方法也可使用第二個(gè)和第三個(gè)參數(shù),表示填充開(kāi)始的位置和結(jié)束的位置
數(shù)組實(shí)例的 entries(),keys() 和 values()
- 遍歷器方法,分別返回鍵數(shù)組,值數(shù)組,鍵值對(duì)數(shù)組(這三個(gè)方法扔數(shù)組里,沒(méi)一點(diǎn)卵用)
for (let index of ['a', 'b'].keys()) {
console.log(index);
}
// 0
// 1
for (let elem of ['a', 'b'].values()) {
console.log(elem);
}
// 'a'
// 'b'
for (let [index, elem] of ['a', 'b'].entries()) {
console.log(index, elem);
}
// 0 "a"
// 1 "b"
數(shù)組實(shí)例的 includes()
- 與字符串的includes類似,檢查數(shù)組內(nèi)有沒(méi)有某個(gè)值,可添加第二個(gè)參數(shù),表示開(kāi)始位置,超過(guò)數(shù)組長(zhǎng)度返回false,若為負(fù)數(shù),表示倒數(shù),此時(shí)超過(guò)數(shù)組長(zhǎng)度,表示從0開(kāi)始
[1, 2, 3].includes(3, 3);
對(duì)于數(shù)組空位的處理
- 在ES5中對(duì)數(shù)組空位的處理是比較不一致的,規(guī)則如下
- forEach(), filter(), every() 和some()都會(huì)跳過(guò)空位。
- map()會(huì)跳過(guò)空位,但會(huì)保留這個(gè)值
- join()和toString()會(huì)將空位視為undefined,而undefined和null會(huì)被處*
理成空字符串。
// forEach方法
[,'a'].forEach((x,i) => console.log(i)); // 1
// filter方法
['a',,'b'].filter(x => true) // ['a','b']
// every方法
[,'a'].every(x => x==='a') // true
// some方法
[,'a'].some(x => x !== 'a') // false
// map方法
[,'a'].map(x => 1) // [,1]
// join方法
[,'a',undefined,null].join('#') // "#a##"
// toString方法
[,'a',undefined,null].toString() // ",a,,"
- 但是在ES6中對(duì)此類現(xiàn)象做出了改變,ES6中凡是新增的方法及擴(kuò)展運(yùn)算符都將數(shù)組空位視為undefined,for...of也不會(huì)跳過(guò)空位
// entries()
[...[,'a'].entries()] // [[0,undefined], [1,"a"]]
// keys()
[...[,'a'].keys()] // [0,1]
// values()
[...[,'a'].values()] // [undefined,"a"]
// find()
[,'a'].find(x => true) // undefined
// findIndex()
[,'a'].findIndex(x => true) // 0