7 數(shù)組的拓展
#7.1 拓展運(yùn)算符
拓展運(yùn)算符使用(...),類似rest參數(shù)的逆運(yùn)算,將數(shù)組轉(zhuǎn)為用(,)分隔的參數(shù)序列。
console.log(...[1, 2, 3]); // 1 2 3
console.log(1, ...[2,3], 4); // 1 2 3 4
拓展運(yùn)算符主要使用在函數(shù)調(diào)用。
function f (a, b){
console.log(a, b);
}
f(...[1, 2]); // 1 2
function g (a, b, c, d, e){
console.log(a, b, c, d, e);
}
g(0, ...[1, 2], 3, ...[4]); // 0 1 2 3 4
若拓展運(yùn)算符后面是個(gè)空數(shù)組,則不產(chǎn)生效果。
[...[], 1]; // [1]
替代apply方法
// ES6之前
function f(a, b, c){...};
var a = [1, 2, 3];
f.apply(null, a);
// ES6之后
function f(a, b, c){...};
let a = [1, 2, 3];
f(...a);
// ES6之前
Math.max.apply(null, [3,2,6]);
// ES6之后
Math.max(...[3,2,6]);
拓展運(yùn)算符的運(yùn)用
-
(1)復(fù)制數(shù)組:
通常我們直接復(fù)制數(shù)組時(shí),只是淺拷貝,如果要實(shí)現(xiàn)深拷貝,可以使用拓展運(yùn)算符。
// 通常情況 淺拷貝
let a1 = [1, 2];
let a2 = a1;
a2[0] = 3;
console.log(a1,a2); // [3,2] [3,2]
// 拓展運(yùn)算符 深拷貝
let a1 = [1, 2];
let a2 = [...a1];
// let [...a2] = a1; // 作用相同
a2[0] = 3;
console.log(a1,a2); // [1,2] [3,2]
-
(2)合并數(shù)組:
注意,這里合并數(shù)組,只是淺拷貝。
let a1 = [1,2];
let a2 = [3];
let a3 = [4,5];
// ES5
let a4 = a1.concat(a2, a3);
// ES6
let a5 = [...a1, ...a2, ...a3];
a4[0] === a1[0]; // true
a5[0] === a1[0]; // true
-
(3)與解構(gòu)賦值結(jié)合:
與解構(gòu)賦值結(jié)合生成數(shù)組,但是使用拓展運(yùn)算符需要放到參數(shù)最后一個(gè),否則報(bào)錯(cuò)。
let [a, ...b] = [1, 2, 3, 4];
// a => 1 b => [2,3,4]
let [a, ...b] = [];
// a => undefined b => []
let [a, ...b] = ["abc"];
// a => "abc" b => []
#7.2 Array.from()
將 類數(shù)組對(duì)象 和 可遍歷的對(duì)象,轉(zhuǎn)換成真正的數(shù)組。
// 類數(shù)組對(duì)象
let a = {
'0':'a',
'1':'b',
length:2
}
let arr = Array.from(a);
// 可遍歷的對(duì)象
let a = Array.from([1,2,3]);
let b = Array.from({length: 3});
let c = Array.from([1,2,3]).map(x => x * x);
let d = Array.from([1,2,3].map(x => x * x));
#7.3 Array.of()
將一組數(shù)值,轉(zhuǎn)換成數(shù)組,彌補(bǔ)Array方法參數(shù)不同導(dǎo)致的差異。
Array.of(1,2,3); // [1,2,3]
Array.of(1).length; // 1
Array(); // []
Array(2); // [,] 1個(gè)參數(shù)時(shí),為指定數(shù)組長(zhǎng)度
Array(1,2,3); // [1,2,3] 多于2個(gè)參數(shù),組成新數(shù)組
#7.4 find()和findIndex()
find()方法用于找出第一個(gè)符合條件的數(shù)組成員,參數(shù)為一個(gè)回調(diào)函數(shù),所有成員依次執(zhí)行該回調(diào)函數(shù),返回第一個(gè)返回值為true的成員,如果沒(méi)有一個(gè)符合則返回undefined。
[1,2,3,4,5].find( a => a < 3 ); // 1
回調(diào)函數(shù)接收三個(gè)參數(shù),當(dāng)前值、當(dāng)前位置和原數(shù)組。
[1,2,3,4,5].find((value, index, arr) => {
// ...
});
findIndex()方法與find()類似,返回第一個(gè)符合條件的數(shù)組成員的位置,如果都不符合則返回-1。
[1,2,3,4].findIndex((v,i,a)=>{
return v>2;
}); // 2
#7.5 fill()
用于用指定值填充一個(gè)數(shù)組,通常用來(lái)初始化空數(shù)組,并抹去數(shù)組中已有的元素。
new Array(3).fill('a'); // ['a','a','a']
[1,2,3].fill('a'); // ['a','a','a']
并且fill()的第二個(gè)和第三個(gè)參數(shù)指定填充的起始位置和結(jié)束位置。
[1,2,3].fill('a',1,2);
#7.6 entries(),keys(),values()
主要用于遍歷數(shù)組,entries()對(duì)鍵值對(duì)遍歷,keys()對(duì)鍵名遍歷,values()對(duì)鍵值遍歷。
for (let i of ['a', 'b'].keys()){
console.log(i)
}
// 0
// 1
for (let e of ['a', 'b'].values()){
console.log(e)
}
// 'a'
// 'b'
for (let e of ['a', 'b'].entries()){
console.log(e)
}
// 0 'a'
// 1 'b'
#7.7 includes()
用于表示數(shù)組是否包含給定的值,與字符串的includes方法類似。
[1,2,3].includes(2); // true
[1,2,3].includes(4); // false
[1,2,NaN].includes(NaN); // true
第二個(gè)參數(shù)為起始位置,默認(rèn)為0,如果負(fù)數(shù),則表示倒數(shù)的位置,如果大于數(shù)組長(zhǎng)度,則重置為0開始。
[1,2,3].includes(3,3); // false
[1,2,3].includes(3,4); // false
[1,2,3].includes(3,-1); // true
[1,2,3].includes(3,-4); // true
#7.8 flat(),flatMap()
flat()用于將數(shù)組一維化,返回一個(gè)新數(shù)組,不影響原數(shù)組。
默認(rèn)一次只一維化一層數(shù)組,若需多層,則傳入一個(gè)整數(shù)參數(shù)指定層數(shù)。
若要一維化所有層的數(shù)組,則傳入Infinity作為參數(shù)。
[1, 2, [2,3]].flat(); // [1,2,2,3]
[1,2,[3,[4,[5,6]]]].flat(3); // [1,2,3,4,5,6]
[1,2,[3,[4,[5,6]]]].flat('Infinity'); // [1,2,3,4,5,6]
flatMap()是將原數(shù)組每個(gè)對(duì)象先執(zhí)行一個(gè)函數(shù),在對(duì)返回值組成的數(shù)組執(zhí)行flat()方法,返回一個(gè)新數(shù)組,不改變?cè)瓟?shù)組。
flatMap()只能展開一層。
[2, 3, 4].flatMap((x) => [x, x * 2]);
// [2, 4, 3, 6, 4, 8]
8 對(duì)象的拓展
#8.1 屬性的簡(jiǎn)潔表示
let a = 'a1';
let b = { a }; // b => { a : 'a1' }
// 等同于
let b = { a : a };
function f(a, b){
return {a, b};
}
// 等同于
function f (a, b){
return {a:a ,b:b};
}
let a = {
fun () {
return 'leo';
}
}
// 等同于
let a = {
fun : function(){
return 'leo';
}
}
#8.2 屬性名表達(dá)式
JavaScript提供2種方法定義對(duì)象的屬性。
// 方法1 標(biāo)識(shí)符作為屬性名
a.f = true;
// 方法2 字符串作為屬性名
a['f' + 'un'] = true;
延伸出來(lái)的還有:
let a = 'hi leo';
let b = {
[a]: true,
['a'+'bc']: 123,
['my' + 'fun'] (){
return 'hi';
}
};
// b.a => undefined ; b.abc => 123 ; b.myfun() => 'hi'
// b[a] => true ; b['abc'] => 123 ; b['myfun'] => ? ['my' + 'fun'] (){ return 'hi'; }
注意:
屬性名表達(dá)式不能與簡(jiǎn)潔表示法同時(shí)使用,否則報(bào)錯(cuò)。
// 報(bào)錯(cuò)
let a1 = 'aa';
let a2 = 'bb';
let b1 = {[a1]};
// 正確
let a1 = 'aa';
let b1 = { [a1] : 'bb'};
#8.3 Object.is()
Object.is() 用于比較兩個(gè)值是否嚴(yán)格相等,在ES5時(shí)候只要使用相等運(yùn)算符(==)和嚴(yán)格相等運(yùn)算符(===)就可以做比較,但是它們都有缺點(diǎn),前者會(huì)自動(dòng)轉(zhuǎn)換數(shù)據(jù)類型,后者的NaN不等于自身,以及+0等于-0。
Object.is('a','a'); // true
Object.is({}, {}); // false
// ES5
+0 === -0 ; // true
NaN === NaN; // false
// ES6
Object.is(+0,-0); // false
Object.is(NaN,NaN); // true
#8.4 Object.assign()
Object.assign()方法用于對(duì)象的合并,將原對(duì)象的所有可枚舉屬性復(fù)制到目標(biāo)對(duì)象。
基礎(chǔ)用法:
第一個(gè)參數(shù)是目標(biāo)對(duì)象,后面參數(shù)都是源對(duì)象。
let a = {a:1};
let b = {b:2};
Object.assign(a,b); // a=> {a:1,b:2}
注意:
- 若目標(biāo)對(duì)象與源對(duì)象有同名屬性,則后面屬性會(huì)覆蓋前面屬性。
let a = {a:1, b:2};
let b = {b:3, c:4};
Object.assign(a, b); // a => {a:1, b:3, c:4}
- 若只有一個(gè)參數(shù),則返回該參數(shù)。
let a = {a:1};
Object.assign(a) === a; // true
- 若參數(shù)不是對(duì)象,則先轉(zhuǎn)成對(duì)象后返回。
typeof Object.assign(2); // 'object'
- 由于
undefined或NaN無(wú)法轉(zhuǎn)成對(duì)象,所以做為參數(shù)會(huì)報(bào)錯(cuò)。
Object.assign(undefined) // 報(bào)錯(cuò)
Object.assign(NaN); // 報(bào)錯(cuò)
-
Object.assign()實(shí)現(xiàn)的是淺拷貝。
Object.assign()拷貝得到的是這個(gè)對(duì)象的引用。這個(gè)對(duì)象的任何變化,都會(huì)反映到目標(biāo)對(duì)象上面。
let a = {a: {b:1}};
let b = Object.assign({},a);
a.a.b = 2;
console.log(b.a.b); // 2
- 將數(shù)組當(dāng)做對(duì)象處理,鍵名為數(shù)組下標(biāo),鍵值為數(shù)組下標(biāo)對(duì)應(yīng)的值。
Object.assign([1, 2, 3], [4, 5]); // [4, 5, 3]