拓展運算符
1.由三個點組成(...),將一個數組轉爲用逗號分隔的參數序列
2.擴展運算符後面還可以放置表達式,貌似僅限數組中使用
const arr = [
...(x > 0 ? ['a'] : []),
'b',
];
3.後面是空數組,不產生任何效果。
4.擴展運算符如果單獨放在括號中,JavaScript 引擎就會認爲這是函數調用。如果這時不是函數調用,就會報錯。
//這種情況:
(...[1])
替代函數的 apply 方法
1.不再需要apply()將數組轉化爲函數參數:
function f(a,b){}
let arr = [0,1];
//ES5
f.apply(null,arr)
//ES6
f(...arr)
2.數組Math.max方法:
Math.max(...[1,2,3])
3.數組push數組:
let arr1 = [1,2];
let arr2 = [3,4];
arr1.push(...arr2); //[1,2,3,4]
4.用數組創建Date實例:
new Date(...[2015, 1, 1]); //Sun Feb 01 2015 00:00:00 GMT+0800 (中國標準時間)
應用
1.複製數組:(數組時複合數據類型,直接複製只是複製了指針 -- 修改克隆數組會導致原數組的改變)
在ES5中使用concat()方法,什麼是concat方法?
示例:
let a = [1,2];
let cloneA = a.concat(); //返回a的副本
cloneA[0] = 2;
a; //[1,2]
ES6拓展寫法:
let a = [1,2];
//寫法1
let cloneA = [...a];
//寫法2
let [...a] = cloneA;
2.合併數組:
[...arr1 , ...arr2 , ...arr3]
它屬於淺拷貝(如果修改了原數組的成員,會同步反映到新數組)
let a1 = [{name:"jack"}];
let a2 = [{age:20}];
let ES6 = [...a1 , ...a2];
let ES5 = a1.concat(a2);
ES6[0].name; //jack
ES5[0].name; //jack
a1[0].name = 'tom';
console.log(ES5[0].name) //tom
console.log(ES6[0].name) //tom
3.與解構賦值相結合(用於生成數組)
var list = [1,2,3,45]
ES5:
let a= list[0],
rest = list.slice(1);
console.log(a,rest); // 1 , [2,3,45]
ES6:
let [b,...restb] = list;
console.log(b ,restb) // 1 , [2,3,45]
拓展運算符,只能放在參數的最後一位,否則會報錯
let [...arr , last ] = [ 1, 2 , 3 , 4 ]; //error
4.可以將字符串轉爲數組
[..."hello"] //['h','e','l','l','o']
能夠正確識別四個字節的 Unicode 字符,涉及到操作四個字節的 Unicode 字符的函數,最好都用擴展運算符改寫。
5.實現Iterator接口的對象,只要定義了遍歷器接口的對象都可以轉爲真正數組:
let arr = [...nodeList]
對於沒有部署遍歷器的類數組對象,可以使用Array.from轉換爲數組:
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
6.Map,Set解構,Generator函數同上
如果對沒有 Iterator 接口的對象,使用擴展運算符,將會報錯。
Array.from() - 將兩類對象轉爲真正的數組(類似數組的對象,可遍歷對象)
0.類數組對象的本質特徵:具有length屬性。
1.如果參數是一個真正的數組,Array.from
會返回一個一模一樣的新數組。
2.Array.from
可以接受第二個參數,作用類似於數組的map
方法,用來對每個元素進行處理,將處理後的值放入返回的數組。
Array.from([1,2,3], (x) => x * x); //[1,4,9]
技巧:
1、提取DOM結點內容:
let spans = document.querySelectorAll('span.name');
// Array.from()
let names2 = Array.from(spans, s => s.textContent)
2、將數組中空位填成0:
Array.from([ 1, ,2 , , 3] , (n) => n || 0 );
//[1,0,2,0,3]
3.若map
函數裏面用到了this
關鍵字,還可以傳入Array.from
的第三個參數,用來綁定this
4.只要有一個原始的數據結構,你就可以先對它的值進行處理,然後轉成規範的數組結構,進而就可以使用數量衆多的數組方法。
Array.from( { length : 2 } , () => 'jack' ); //['jack' , 'jack']
5.字符串轉爲數組,然後返回字符串的長度。因爲它能正確處理各種 Unicode 字符,可以避免 JavaScript 將大於\uFFFF
的 Unicode 字符,算作兩個字符的 bug。
function countSymbols(string) {
return Array.from(string).length;
}
Array.of() - 將一組值,轉換爲數組
1.可以用來替代Array()
或new Array()
,並且不存在由於參數不同而導致的重載。它的行爲非常統一。
Array.of() // []
Array.of(undefined) // [undefined]
Array.of(1) // [1]
Array.of(1, 2) // [1, 2]
2.Array.of
總是返回參數值組成的數組。如果沒有參數,就返回一個空數組。
數組實例的coplyWithin() - 使用這個方法,會修改當前數組
1.用法:
Array.prototype.copyWithin(target, start = 0, end = this.length)
它接受三個參數。
- target(必需):從該位置開始替換數據。如果爲負值,表示倒數。
- start(可選):從該位置開始讀取數據,默認爲 0。如果爲負值,表示倒數。
- end(可選):到該位置前停止讀取數據,默認等於數組長度。如果爲負值,表示倒數。
這三個參數都應該是數值,如果不是,會自動轉爲數值。
let arr = [1, 2, 3, 4, 5, 6, 7];
let arr1 = arr.copyWithin(0, 3)
log(arr1) //[4,5,6,7,5,6,7]
//表示:將 從3號位開始 到 數組結束的成員 [4,5,6,7] 複製到 從零開始的位置
// 將3號位複製到0號位
[1, 2, 3, 4, 5].copyWithin(0, 3, 4)
// [4, 2, 3, 4, 5]
// -2相當於3號位,-1相當於4號位
[1, 2, 3, 4, 5].copyWithin(0, -2, -1)
// [4, 2, 3, 4, 5]
// 將3號位複製到0號位
[].copyWithin.call({length: 5, 3: 1}, 0, 3)
// {0: 1, 3: 1, length: 5}
// 將2號位到數組結束,複製到0號位
let i32a = new Int32Array([1, 2, 3, 4, 5]);
i32a.copyWithin(0, 2);
// Int32Array [3, 4, 5, 4, 5]
// 對於沒有部署 TypedArray 的 copyWithin 方法的平臺
// 需要採用下面的寫法
[].copyWithin.call(new Int32Array([1, 2, 3, 4, 5]), 0, 3, 4);
// Int32Array [4, 2, 3, 4, 5]
數組實例的find()方法和findIndex()
find():它的參數是一個回調函數,所有數組成員依次執行該回調函數,直到找出第一個返回值爲true
的成員,然後返回該成員,未成立返回undeifned。
//找出第一個大於9的成員
let arr = [1, 2, 3, 4, 5, 6, 7,10,11];
let arr1 = arr.find((value,index,arr)=>{
return value > 9
})
l(arr1) //10
findIndex,符合條件返回數組成員位置,不符合返回-1
let arr = [1, 2, 3, 4, 5, 6, 7,10,11];
let arr1 = arr.findIndex((value,index,arr)=>{
return value > 9
})
l(arr1) //7
這兩個方法都可以接受第二個參數,用來綁定回調函數的this
對象:
let arr = [1, 2, 30];
function f(v) {
return v > this.age;
}
let person = {
name: "Job",
age: 20
};
let a = arr.find(f, person);
a //30
find
函數接收了第二個參數person
對象,回調函數中的this
對象指向person
對象。
這兩個方法都可以發現NaN
,彌補了數組的indexOf
方法的不足。
[NaN].indexOf(NaN)
// -1
[NaN].findIndex(y => Object.is(NaN, y))
// 0
fill()方法 - 使用給定值,填充一個數組(修改原數組)
['a','b'].fill(1)
//[ 1 , 1 ]
new Array(3).fill(1);
//[1,1,1]
1.數組中已有的元素,會被全部抹去。
2.可以接受第二個和第三個參數,用於指定填充的起始位置和結束位置。
3.如果填充的類型爲對象,那麼被賦值的是同一個內存地址的對象,而不是深拷貝對象。
let arr = new Array(2).fill({name:"jack"});
arr //[{name:"jack"},{name:"jack"}]
arr[0].name = 'tom'
arr //[{name:"tom"},{name:"tom"}]
let arr1 = new Array(2).fill([]);
arr1[0].push(5)
arr1 //[ [5] , [5] , [5] ]
entries(),keys() 和 values()
1.用於遍歷數組,都返回一個遍歷器對象。
2.可以用for...of
循環進行遍歷,唯一的區別是keys()
是對鍵名的遍歷、values()
是對鍵值的遍歷,entries()
是對鍵值對的遍歷。
let arr = [ "a" , "b" ];
for (let i of arr.keys()){
console.log(i); //0 1
}
for(let e of arr.values()){
console.log(e); //a b
}
for(let [i,e] of arr.entries()){
console.log(i,e); //0 "a" 1"b"
}
3.不使用for...of
循環,可以手動調用遍歷器對象的next
方法,進行遍歷
let arr2 = ['a','b','c'];
let entries = arr2.entries();
entries.next().value; //[0,"a"]
entries.next().value; //[1,"b"]
entries.next().value; //[2,"c"]
let values = arr2.values();
values.next().value; //a
values.next().value; //b
values.next().value; //c
let keys = arr2.keys();
keys.next().value; //0
keys.next().value; //1
keys.next().value; //2
includes() - 返回一個布爾值,表示某個數組是否包含給定的值
0.對象數組無效。
let arr3 = [{name:'jack'},{name:"tom"}];
let obj = {name:'jack'};
let bool = arr3.includes(obj); //false
1.該方法的第二個參數表示搜索的起始位置,默認爲0
。
2.如果第二個參數爲負數,則表示倒數的位置,如果這時它大於數組長度,則會重置爲從0
開始。
3.indexOf使用===,會造成對NaN的誤判,includes不會
4.Map 和 Set 數據結構有一個has
方法,需要注意與includes
區分。
- Map 結構的
has
方法,是用來查找鍵名的,比如Map.prototype.has(key)
、WeakMap.prototype.has(key)
、Reflect.has(target, propertyKey)
。 - Set 結構的
has
方法,是用來查找值的,比如Set.prototype.has(value)
、WeakSet.prototype.has(value)
。
數組實例的 flat(),flatMap()
1.flat()
用於將嵌套的數組變成一維的數組,該方法返回一個新數組,對原數據沒有影響。
2.flat()
默認只會將二維數組轉換,如果想更深層,在()中寫入層數
let arr = [1,2,[3,4]];
arr = arr.flat(); //[1,2,3,4];
let arr1 = [1,2,3,[4,5,[6,7]]];
arr1 = arr1.flat(2); //[1,2,3,4,5,6,7]
3.如果不管有多少層嵌套,都要轉成一維數組,可以用Infinity
關鍵字作爲參數。
4.flat()
方法會跳過空位。
5.flatMap()
方法對原數組的每個成員執行一個函數.
// 相當於 [[2, 4], [3, 6], [4, 8]].flat()
[2, 3, 4].flatMap((x) => [x, x * 2])
// [2, 4, 3, 6, 4, 8]
6.flatMap()
只能展開一層數組。
// 相當於 [[[2]], [[4]], [[6]], [[8]]].flat()
[1, 2, 3, 4].flatMap(x => [[x * 2]])
// [[2], [4], [6], [8]]
7.flatMap()
方法首先使用映射函數映射每個元素,然後將結果壓縮成一個新數組。它與 map 和 深度值1的 flat 幾乎相同,但 flatMap
通常在合併成一種方法的效率稍微高一些。
8.flatMap()
方法的參數是一個遍歷函數,該函數可以接受三個參數,分別是當前數組成員、當前數組成員的位置(從零開始)、原數組。
9.flatMap()
方法還可以有第二個參數,用來綁定遍歷函數裏面的this
。
注意:
數組的空位
1.數組的某一個位置沒有任何值。
var arr = new Array(3);
arr //[, , ,]
2.空位不是undefined
,一個位置的值等於undefined
,依然是有值的,可以用in運算符求證:
in:如果指定的屬性在指定的對象或其原型鏈中,則in
運算符返回true
。
0 in [undefined, undefined, undefined] // true
0 in [, , ,] // false
3.ES5 對空位的處理,已經很不一致了,大多數情況下會忽略空位。
forEach()
,filter()
,reduce()
,every()
和some()
都會跳過空位。map()
會跳過空位,但會保留這個值join()
和toString()
會將空位視爲undefined
,而undefined
和null
會被處理成空字符串。
4.Array.from
方法會將數組的空位,轉爲undefined。
5.擴展運算符(...
)也會將空位轉爲undefined
。
6.copyWithin()
會連空位一起拷貝。
7.fill()
會將空位視爲正常的數組位置。
8.for...of
循環也會遍歷空位。
9.entries()
、keys()
、values()
、find()
和findIndex()
會將空位處理成undefined
。