參考:https://es6.ruanyifeng.com/#docs/array
一、擴充運算符
1、含義
擴充運算符(spread)是三個點(
...
)。它好比 rest 參數的逆運算,将一個數組轉為用逗号分隔的參數序列。
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>]
- 該運算符主要用于函數調用。
- 擴充運算符與正常的函數參數可以結合使用
- 擴充運算符後面還可以放置表達式。
- 如果擴充運算符後面是一個空數組,則不産生任何效果。
- 隻有函數調用時,擴充運算符才可以放在圓括号中,否則會報錯。
2、替代函數的 apply 方法
由于擴充運算符可以展開數組,是以不再需要
apply
方法,将數組轉為函數的參數了。
// ES5 的寫法
function f(x, y, z) {
// ...
}
var args = [0, 1, 2];
f.apply(null, args);
// ES6的寫法
function f(x, y, z) {
// ...
}
let args = [0, 1, 2];
f(...args);
面是擴充運算符取代
apply
方法的一個實際的例子,應用
Math.max
方法,簡化求出一個數組最大元素的寫法。
// ES5 的寫法
Math.max.apply(null, [14, 3, 77])
// ES6 的寫法
Math.max(...[14, 3, 77])
// 等同于
Math.max(14, 3, 77);
上面代碼中,由于 JavaScript 不提供求數組最大元素的函數,是以隻能套用
Math.max
函數,将數組轉為一個參數序列,然後求最大值。有了擴充運算符以後,就可以直接用
Math.max
了。
另一個例子是通過
push
函數,将一個數組添加到另一個數組的尾部。
// ES5的 寫法
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
Array.prototype.push.apply(arr1, arr2);
// ES6 的寫法
let arr1 = [0, 1, 2];
let arr2 = [3, 4, 5];
arr1.push(...arr2);
上面代碼的 ES5 寫法中,
push
方法的參數不能是數組,是以隻好通過
apply
方法變通使用
push
方法。有了擴充運算符,就可以直接将數組傳入
push
方法。
// ES5
new (Date.bind.apply(Date, [null, 2015, 1, 1]))
// ES6
new Date(...[2015, 1, 1]);
3、擴充運算符的應用
1)複制數組
數組是複合的資料類型,直接複制的話,隻是複制了指向底層資料結構的指針,而不是克隆一個全新的數組。
const a1 = [1, 2];
const a2 = a1;
a2[0] = 2;
a1 // [2, 2]
上面代碼中,
a2
并不是
a1
的克隆,而是指向同一份資料的另一個指針。修改
a2
,會直接導緻
a1
的變化。
ES5 隻能用變通方法來複制數組。
const a1 = [1, 2];
const a2 = a1.concat();
a2[0] = 2;
a1 // [1, 2]
上面代碼中,
a1
會傳回原數組的克隆,再修改
a2
就不會對
a1
産生影響。
擴充運算符提供了複制數組的簡便寫法。
const a1 = [1, 2];
// 寫法一
const a2 = [...a1];
// 寫法二
const [...a2] = a1;
//a2都是a1的克隆。
2)合并數組
擴充運算符提供了數組合并的新寫法。
const arr1 = ['a', 'b'];
const arr2 = ['c'];
const arr3 = ['d', 'e'];
// ES5 的合并數組
arr1.concat(arr2, arr3);
// [ 'a', 'b', 'c', 'd', 'e' ]
// ES6 的合并數組
[...arr1, ...arr2, ...arr3]
// [ 'a', 'b', 'c', 'd', 'e' ]
不過,這兩種方法都是淺拷貝,使用的時候需要注意。
const a1 = [{ foo: 1 }];
const a2 = [{ bar: 2 }];
const a3 = a1.concat(a2);
const a4 = [...a1, ...a2];
a3[0] === a1[0] // true
a4[0] === a1[0] // true
上面代碼中,
a3
和
a4
是用兩種不同方法合并而成的新數組,但是它們的成員都是對原數組成員的引用,這就是淺拷貝。如果修改了引用指向的值,會同步反映到新數組。
3)與解構指派結合
擴充運算符可以與解構指派結合起來,用于生成數組。
// ES5
a = list[0], rest = list.slice(1)
// ES6
[a, ...rest] = list
注意:如果将擴充運算符用于數組指派,隻能放在參數的最後一位,否則會報錯。
const [...butLast, last] = [1, 2, 3, 4, 5];
// 報錯
const [first, ...middle, last] = [1, 2, 3, 4, 5];
// 報錯
4)字元串
擴充運算符還可以将字元串轉為真正的數組。
[...'hello']
// [ "h", "e", "l", "l", "o" ]
5)實作了 Iterator 接口的對象
任何定義了周遊器(Iterator)接口的對象(參閱 Iterator 一章),都可以用擴充運算符轉為真正的數組。
let nodeList = document.querySelectorAll('div');
let array = [...nodeList];
上面代碼中,
querySelectorAll
方法傳回的是一個
NodeList
對象。它不是數組,而是一個類似數組的對象。這時,擴充運算符可以将其轉為真正的數組,原因就在于
NodeList
對象實作了 Iterator 。
對于那些沒有部署 Iterator 接口的類似數組的對象,擴充運算符就無法将其轉為真正的數組。擴充運算符就會報錯。
6)Map 和 Set 結構,Generator 函數
擴充運算符内部調用的是資料結構的 Iterator 接口,是以隻要具有 Iterator 接口的對象,都可以使用擴充運算符,比如 Map 結構。
let map = new Map([
[1, 'one'],
[2, 'two'],
[3, 'three'],
]);
let arr = [...map.keys()]; // [1, 2, 3]
Generator 函數運作後,傳回一個周遊器對象,是以也可以使用擴充運算符。
const go = function*(){
yield 1;
yield 2;
yield 3;
};
[...go()] // [1, 2, 3]
上面代碼中,變量
go
是一個 Generator 函數,執行後傳回的是一個周遊器對象,對這個周遊器對象執行擴充運算符,就會将内部周遊得到的值,轉為一個數組。
如果對沒有 Iterator 接口的對象,使用擴充運算符,将會報錯。
二、Array.from()
Array.from
方法用于将兩類對象轉為真正的數組:類似數組的對象(array-like object)和可周遊(iterable)的對象(包括 ES6 新增的資料結構 Set 和 Map)
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
// ES5的寫法
var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']
// ES6的寫法
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
實際應用中,常見的類似數組的對象是 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 args = Array.from(arguments);
// ...
}
上面代碼中,
querySelectorAll
方法傳回的是一個類似數組的對象,可以将這個對象轉為真正的數組,再使用
filter
方法。
隻要是部署了 Iterator 接口的資料結構,
Array.from
都能将其轉為數組。
數組建立
1、Array.of()
将參數中所有值作為元素形成數組。
console.log(Array.of(1, 2, 3, 4)); // [1, 2, 3, 4]
// 參數值可為不同類型
console.log(Array.of(1, '2', true)); // [1, '2', true]
// 參數為空時傳回空數組
console.log(Array.of()); // []
2、Array.from()
方法用于将兩類對象轉為真正的數組:類似數組的對象(array-like object)和可周遊(iterable)的對象(包括 ES6 新增的資料結構 Set 和 Map)。
下面是一個類似數組的對象,
Array.from
将它轉為真正的數組。
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
// ES5的寫法
var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']
// ES6的寫法
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']