概覽
ES6引進了一些新的數組方法。
擴展運算符(Spread)+剩餘操作符(Rest)
含義: 擴展運算符(spread)是三個點
...
,它如同rest參數的逆運算,將一個數組轉爲用逗號分隔的參數序列。
- 剩餘操作符提取數組,用於剩餘參數和結構。
- 擴展操作符將數組元素轉換成函數調用的參數或者數組字面量的元素。
console.log(...[1, 2, 3]); // 1 2 3
console.log(1, ...[2, 3, 4], 5); //1 2 3 4 5
Rest(函數參數) 和 Spread(數組運算符) 主要是應用 ... 運算符,完成值的聚合和分解。
// 1.rest得到的是一個真正的數組,而不是一個僞數組。
const getOptions = function(...args){
console.log(args.join());
}
const arr = [123];
getOptions(...arr); // 123
// 2.rest可以搭配箭頭函數使用,達到取得所有參數的目的。
const getOption = (...args)=>{
console.log(args);
}
let arrs = [1,2,3];
getOption(...arrs); // [1,2,3]
// 3.spread可以用於解構時,聚合所得的值。
const opt1 = 'one';
const opt2 = ['two','three','four'];
console.log([opt1,...opt2]); // ["one", "two", "three", "four"]
//4.spread可以用於數組定義。
const opts = ["one", "two", "three", "four"];
const config = ['other', ...opts]
該運算符主要用於函數的調用。
function push(array, ...items){
array.push(...items);
}
function add(x, y){
return x + y;
}
const numbers = [4, 38];
console.log(add(...numbers));; // 42
從上面的代碼可以看出,該運算符可以將一個數組變成爲參數序列。
function f(v, w, x, y, z){
console.log([v, w, x, y, z]);
}
const args = [0, 1];
f(-1, ...args, 2, ...[3]) // [-1, 0, 1, 2, 3]
擴展運算符後面放置表達式。
const arr = [
...(x > 0 ? ['a'] : []),
'b',
]
如果擴展運算符後面是一個空數組,則不產生任何效果。
console.log([...[], 1]); // [1]
擴展運算符應用
替代數組的apply方法:
// 由於擴展運算符可以展開數組,所以不需要使用apply方法將數組轉爲函數的參數。
// ES5 寫法
function f(x,y,z){
console.log(x,y,z);
}
const args = [0,1,2];
f.apply(null,args) // 0 1 2
// ES6 寫法
function f1(x,y,z){
console.log(x,y,z);
}
f1(...args) // 0 1 2
// ES5 寫法
console.log(Math.max.apply(null,[14,3,77])); //77
// ES6 寫法
console.log(Math.max(...[14,3,77])); //77
//等同於
console.log(Math.max(14,3,77)); //77
// ES5 寫法
const arr1 = [0,1,2];
const arr2 = [3,4,5];
Array.prototype.push.apply(arr1,arr2);
console.log(arr1); // [0, 1, 2, 3, 4, 5]
// ES6 寫法
const arr11 = [0,1,2];
const arr22 = [3,4,5];
arr11.push(...arr22);
console.log(arr11); // [0, 1, 2, 3, 4, 5]
// ES5 寫法
console.log(new (Date.bind.apply(Date, [null , 2015, 1, 1]))); // Sun Feb 01 2015 00:00:00 GMT+0800 (中國標準時間)
// ES6 寫法
console.log(new Date(...[2015, 1, 1])); // Sun Feb 01 2015 00:00:00 GMT+0800 (中國標準時間)
合併數組:
// ES5 寫法
const more = [2,2,2];
console.log([1,2].concat(more)); // [1,2,2,2,2]
// ES6 寫法
console.log([1,2,...more]); // [1,2,2,2,2]
// ES5 寫法
const arr1 = ['a','b'];
const arr2 = ['c','d'];
const arr3 = ['e','f'];
const arr = arr1.concat(arr2,arr3)
console.log(arr); // ["a", "b", "c", "d", "e", "f"]
// ES6 寫法
console.log([...arr1,...arr2,...arr3]); // ["a", "b", "c", "d", "e", "f"]
console.log([1, ...[2,3], 4]); // [1,2,3,4]
與解構賦值結合:
// ES5 寫法
const list = [1,2];
const a = list[0];
const rest = list.slice(1);
console.log(a, rest); // 1 [2]
// ES6 寫法
[a1, ...rest1] = list;
console.log(a1,rest1); // 1 [2]
// 其他例子
const [first,...res] = [1,2,3,4,5];
console.log(first,res); // 1 [2,3,4,5]
const [first1,...res1] = [];
console.log(first1,res1); //undefined []
const [first2,...res2] = ['foo'];
console.log(first2,res2); // 'foo' []
const [...butLast, last] = [1,2,3,4,5] // 報錯 Rest element must be last element
const [first3,...middle, last] = [1,2,3,4,5] // 報錯 Rest element must be last element
函數返回值:
JavaScript的函數只能返回一個值,如果需要返回多個值,只能返回數組或對象。擴展運算符提供瞭解決這個問題的一種變通方法。
字符串:
// 將字符串轉爲真正的數組
console.log([...'hello']); // ['h','e','l','l','o']
// 正確識別32位的Unicode
console.log([...'x\uD83D\uDE80y'].length); // 3
實現了Iterator接口的對象:
任何Iterator接口的對象,都可以用擴展運算符轉爲真正的數組。
對於那些沒有部署Iterator接口的類似數組的對象,擴展運算符就無法將其轉爲真正的數組。
const arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
}
// ES5 轉爲數組
const arrNew1 = [].slice.call(arrayLike);
console.log(arrNew1); // ['a','b','c']
// ES6 轉爲數組
const arrNew2 = Array.from(arrayLike); // ['a', 'b', 'c']
console.log(arrNew2); // ['a', 'b', 'c']
// Uncaught TypeError: arrayLike is not iterable.
const arrNew3 = [...arrayLike];
Map和Set結構、Generator函數:
// Map結構
let map = new Map([
[1,'one'],
[2,'two'],
[3,'three'],
])
let arr1 = [...map.keys()];
let arr2 = [...map.values()];
console.log(arr1,arr2); // [1, 2, 3] ["one", "two", "three"]
// Set結構
let set = new Set([11,-1,6]);
let arrNew = [...set];
console.log(arrNew); // [11,-1,6]
// Generator函數
const go = function*(){
yield 1;
yield 2;
yield 3;
}
console.log([...go()]); // [1,2,3]
const obj = {
* [Symbol.iterator](){
yield 'a';
yield 'b';
yield 'c';
}
}
console.log([...obj]); // ['a','b','c']
// 對於沒有Iterator接口的對象,使用擴展運算符會報錯
const obj1 = {
a:1,
b:2,
}
console.log([...obj1]); // Uncaught TypeError: obj1 is not iterable
數組類方法Array.from()
Array.from()
方法用於將兩類對象轉爲真正的數組:類似數組的對象(array-like object)和可遍歷(iterator)對象(包括ES6新增的數據結構Set和Map)。
類似數組對象轉爲數組:
let arrayLike = {
'0':'a',
'1':'b',
'2':'c',
length:3
}
// ES5 寫法
let arrNew1 = [].slice.call(arrayLike);
console.log(arrNew1); // ['a','b','c']
// ES6 寫法
let arrNew2 = Array.from(arrayLike);
console.log(arrNew2); // ['a','b','c']
NodeList對象轉爲數組:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<p>1</p>
<p>2</p>
<p>3</p>
<script>
const ps = document.querySelectorAll('p');
Array.from(ps).forEach(function(p){
console.log(p);
})
Array.from(ps).map(function(val){
console.log(val);
})
Array.from(ps, x =>console.log(x))
</script>
</body>
</html>
arguments對象轉爲數組:
function foo(x = 0,y = 12) {
let args = Array.from(arguments)
console.log(args);
}
foo(); // []
foo(1); // [1]
foo(1,2); // [1,2]
字符串(Iterator接口)轉爲數組:
console.log(Array.from('hello')); // ["h", "e", "l", "l", "o"]
Set結構(Iterator接口)轉爲數組:
let nameSet = new Set(['a','b']);
console.log(Array.from(nameSet)); // ["a", "b"]
操作數組:
console.log(Array.from([1,2,3])); // [1,2,3]
類似數組的對象,特殊情況:
console.log(Array.from({length:3})); // [undefined,undefined,undefined]
console.log(Array.from({length:2},()=>'jack')); // ["jack", "jack"]
轉數組兼容性考慮:
const toArray = (()=>
Array.from?Array.from:obj=>[].slice.call(obj)
)();
將數組中布爾值爲false的成員轉爲0:
console.log(Array.from([1,,2,,3],(n)=>n||0)); // [1, 0, 2, 0, 3]
返回各種數據的類型:
function typesOf(){
return Array.from(arguments,value=>typeof value)
}
console.log(typesOf(null,[],NaN)); // ["object", "object", "number"]
避免將大於\uFFFF的Unicode字符算作兩個字符的bug:
function countSymbols(string){
return Array.from(string).length
}
數組類方法Array.of()
將一組值轉換爲數組,彌補數組構造函數Array的不足。
Array.of()
總是返回參數值組成的數組,如果沒有參數,就返回一個空數組。
console.log(Array.of()); // []
console.log(Array.of(undefined)); //[undefined]
console.log(Array.of(null)); // [null]
console.log(Array.of(1)); // [1]
console.log(Array.of(1,2)); // [1,2]
console.log(Array.of(3,4,7)); // [3,4,7]
Array 子類的構造函數會繼承所有的 Array 類的方法,包括 of() 方法
class MyArray extends Array {
}
console.log(MyArray.of(3, 11, 8) instanceof MyArray); // true
console.log(MyArray.of(3).length === 1); // true
數組原型方法copyWithin()
會在當前數組內部制定位置的成員複製到其他位置(會覆蓋原有成員),會返回當前數組。
Array.prototype.copyWithin(target,start=0,end=this.length)
- target(必選):從當前位置開始替換數據。
- start(可選):從該位置開始讀取數據,默認0.如果爲負值,表示倒數。
- end(可選):到該位置前停止讀取數據,默認等於數組長度。如果爲負值,表示倒數。
// 將3號位到最後一位複製0號位開始往後排
let arr1 = [1,2,3,4,5]
arr1.copyWithin(0,3);
console.log(arr1); // [4, 5, 3, 4, 5]
// 將3號位複製到0號位
let arr2 = [1,2,3,4,5]
arr2.copyWithin(0,3,4);
console.log(arr2); // [4, 2, 3, 4, 5]
// -2相當於3號位,-1相當於4號位
let arr3 = [1,2,3,4,5];
arr3.copyWithin(0,-2,-1);
console.log(arr3); // [4, 2,3 , 4, 5]
// 將3號位複製到0號位
let arr4 = [].copyWithin.call({length:5,3:1},0,3);
console.log(arr4); // {0: 1, 3: 1, length: 5}
// 將2號位到數組結束,複製到0號位
let arr5 = new Int32Array([1,2,3,4,5])
arr5.copyWithin(0,2)
console.log(arr5); // Int32Array(5) [3, 4, 5, 4, 5]
// 對於沒有部署TypedArray的copyWithin方法的平臺
// 需要採用下面的寫法
let arr6 = [].copyWithin.call(new Int32Array([1,2,3,4,5]),0,3,4);
console.log(arr6); // Int32Array(5) [4, 2, 3, 4, 5]
數組原型方法find()
和findIndex()
find()
方法用於找出第一個符合條件的數組成員。它的參數是一個回調函數,所有的數組成員依次執行該回調函數,直到找出第一個返回值爲true的成員,然後返回該成員,如果沒有符合條件的成員,則返回undefined。
findIndex
方法與find()
方法非常類似,返回第一個符合條件的數組成員的位置,如果所有成員都不符合條件,則返回-1.
let num = [1,4,-5,10].find(n=>n < 0)
console.log(num); // -5
let num1 = [1,4,-5,10].find(n=>n > 11)
console.log(num1); // undefined
let num2 = [1,4,-5,10].findIndex(n=>n < 0)
console.log(num2); // -5
let num3 = [1,4,-5,10].findIndex(n=>n > 11)
console.log(num3); // -1
接受3個參數,依次爲當前的值,當前的位置和原數組:
// find返回value
let num4 = [1,5,10,15].find(function(value,index,arr){
return value > 9;
})
console.log(num4); // 10
//findIndex返回index
let num5 = [1,5,10,15].findIndex(function(value,index,arr){
return value > 9;
})
console.log(num5); // 2
將數組的空缺作爲undefined
處理:
let num6 = ['a',,'c'].find(x=>x===undefined)
console.log(num6); // undefined
let num7 = ['a',,'c'].findIndex(x=>x===undefined)
console.log(num7); // 1
通過findIndex
方法尋找NaN
:
indexOf()
一個衆所周知的侷限在於它無法尋找NaN
.
console.log([NaN].indexOf(NaN)); // -1
console.log([NaN].findIndex(y=>Object.is(NaN,y))); // 0
// 也可以創建輔助函數`elemIs()`
function elemIs(x){
return Object.is.bind(Object, x)
}
console.log([NaN].findIndex(elemIs(NaN))); // 0
數組原型方法fill()
fill(value,start,end)
用給定的值填充數組:
console.log(['a','b','c'].fill(7)); // [7, 7, 7]
數組的空缺不會被特殊處理:
console.log(['a',,'c'].fill(7)); // [7, 7, 7]
console.log(new Array(3).fill(7)); // [7, 7, 7]
限定填充範圍:
console.log(['a','b','c'].fill(7,1,2)); // ["a", 7, "c"]
數組原型方法keys()
、values()
和entries()
——用於遍歷數組;
——都返回遍歷器對象;
——可用for...of
遍歷;
keys()
是對鍵名的遍歷、values()
是對鍵值的遍歷、entries()
是對鍵值對的遍歷。
// `Array.from()` 把迭代器中的內容放入數組
console.log(Array.from(['a','b'].keys())); // [0, 1]
console.log(Array.from(['a','b'].values())); // ['a', 'b']
console.log(Array.from(['a','b'].entries())); // [[0, 'a'], [1, 'b']]
// 展開操作符(...)將迭代器轉換成數組
console.log(...['a','b'].keys()); // 0 1
console.log(...['a','b'].values()); // 'a' 'b'
console.log(...['a','b'].entries()); // [0, 'a'] [1, 'b']
// `for..of`遍歷
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"
數組原型方法includes()
includes()
方法判斷某個數組是否包含給定的值,返回true
或者false
。
console.log([1,2,3].includes(2)); // true
console.log([1,2,3].includes(4)); // false
console.log([1,2,NaN].includes(NaN)); // true
// 第二個參數表示搜索的起始位置,默認爲0。如果爲負數,則表示倒數的位置,如果這時大於數組的長度則會重置爲從0開始
console.log([1,2,3].includes(2,-4)); // true
console.log([1,2,3].includes(2,-3)); // true
console.log([1,2,3].includes(2,-2)); // true
console.log([1,2,3].includes(2,-1)); // false
console.log([1,2,3].includes(2,0)); // true
console.log([1,2,3].includes(2,1)); // true
console.log([1,2,3].includes(2,2)); // false
console.log([1,2,3].includes(2,3)); // false
console.log([1,2,3].includes(2,4)); // false