ECMAScript 6的一些注意點 第三部分(數組的拓展)

拓展運算符

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,而undefinednull會被處理成空字符串。

4.Array.from方法會將數組的空位,轉爲undefined。

5.擴展運算符(...)也會將空位轉爲undefined

6.copyWithin()會連空位一起拷貝。

7.fill()會將空位視爲正常的數組位置。

8.for...of循環也會遍歷空位。

9.entries()keys()values()find()findIndex()會將空位處理成undefined

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章