ES6學習筆記二之數組的擴展

Array.from()

Array.from() 方法從類似數組(array-like)或可迭代對象(iterable)創建一個新的數組實例(包括ES6新增的數據結構Set和Map)。

Array.from(arrayLike[, mapFn[, thisArg]])

如下是一個類數組的對象,Array.from將它轉換爲一個真正的數組。

// [].slice.call(arrayLike); es5
let arrayLike = {
  '0': 'a',
  '1': 'b',
  '8': 'c',
  length: 5
}
var arr1 = Array.from(arrayLike);
console.log(arr1);

結果是一個5個元素的數組,其中第一個元素是a,第二個元素是b,第三第四第五個元素是undefined。length制定數組的長度,沒有這個屬性數組長度爲0,超過數組索引的值無效,如上述的8。

實際應用中,常見的類似數組的對象是DOM操作返回的NodeList集合,以及函數內部的arguments對象。Array.from都可以將他們轉換爲真正的數組。

// NodeList對象
let ps = document.querySelectAll('p');
Array.from(ps).forEach(function(p) {
  console.log(p);
})
// arguments對象
(function(){]
  var args = Array.from(arguments);
  console.log(args);
})(1,2,3)

事實上,只要是部署了Iterator接口的數據結構,Array.from都能將其轉換爲數組。比如字符串、Set、Map,以及自定義的Iterator。

對於還沒有部署該方法的瀏覽器,可以用Array.prototype.slice方法替代。

const toArray = (() => Array.from ? Array.from : [].slice.call(obj))();

Array.from() 方法有一個可選參數 mapFn,讓你可以在最後生成的數組上再執行一次 map 方法後再返回。也就是說 Array.from(obj, mapFn, thisArg) 就相當於 Array.from(obj).map(mapFn, thisArg), 除非創建的不是可用的中間數組。

Array.from([1, 2, 3], x => x * x); // [1, 4, 9]
Array.from([1, 2, 3], (x, k) => k); // [0, 1, 2] 返回索引

如果mapFn函數中用到了this關鍵字,還可以傳入第三個參數,用來綁定this。

Array.from()的另一個應用是,將一個字符串轉換爲數組,然後返回字符串的長度。因爲它能正確處理各種Unicode字符,可以避免JavaScript將大於\uFFFF額Unicode字符算作多個字符的bug。

function countSymbols(string) {
  return Array.from(string).length;
}

Array.of()

Array.of方法用於將一組值轉換爲數組。

Array.of(element0[, element1[, ...[, elementN]]])
Array.of(1, 2, 3); // [1, 2, 3]

此方法是彌補數組構造函數的不足,因爲當數組參數只有一個的時候會被當做數組的長度而不會第一個元素看待。

console.log(new Array()); // []
console.log(new Array(1)); // [undefined]
console.log(new Array(1,2)); // [1, 2]

Array.of方法可以使用下面的代碼模擬實現:

function ArrayOf() {
  return [].slice.call(arguments);
}

Array.prototype.copyWithin()

copyWithin() 方法會淺拷貝數組的部分元素到同一數組的不同位置,且不改變數組的大小,返回該數組。
copyWithin 函數是設計爲通用的,其不要求其 this 值必須是一個數組對象。

arr.copyWithin(target, start = 0, end = this.length)
  • target: 必須,表示複製序列到該位置。
  • start: 開始複製元素的起始位置。如果是負數,start 將從末尾開始計算。
  • 開始複製元素的結束位置。copyWithin 將會拷貝到該位置,但不包括 end 這個位置的元素。如果是負數, end 將從末尾開始計算。

以上參數都是以0爲基底。

// 從3號索引開始,從位置0開始複製
[1, 2, 3, 4, 5].copyWithin(0, 3); // [4, 5, 3, 4, 5]
// -2相當於3
[1, 2, 3, 4, 5].copyWithin(0, -2, -1); //[4, 2, 3, 4, 5]
// this不需要指向數組
[].copyWithin.call({length: 5, 3: 1}, 0, 3); // {0: 1, 3: 1, length: 5}

Array.prototype.find()和Array.prototype.findIndex()

正如其名,數組實例的find方法,用於找出第一個符合條件的數組元素。該函數接受一個函數參數,函數有三個參數,如下:

[1, 2, 3, 4, 5].find((item, index, arr) => item > 3); // 4

如果找不到符合條件的值返回undefined。

findIndex方法,找到第一個符合條件元素的索引。參數和find方法一樣。

[1, 2, 3, 4, 5].findIndex((item, index, arr) => item > 3); // 3

如果找不到符合條件的值返回-1。

另外這兩個方法都可以發現NaN,彌補了數組的IndexOf方法的不足。

[NaN].indexOf(NaN); // -1
[NaN].findIndex(y => Object.is(NaN, y)); // 0

Array.prototype.fill()

fill方法將一個數組的所有元素從開始索引填充到具有靜態值的結束索引。
fill 方法故意被設計成通用方法, 也就是說它不需要 this 值必須是個數組對象, 類數組對象也是可以調用該方法的。

fill 方法接受三個參數 value, start 以及 end. start 和 end 參數是可選的, 其默認值分別爲 0 和 this 對象的 length 屬性值.

如果 start 是個負數, 則開始索引會被自動計算成爲 length+start, 其中 length 是 this 對象的 length 屬性值. 如果 end 是個負數, 則結束索引會被自動計算成爲 length+end.

具體要填充的元素區間是 [start, end) , 一個半開半閉區間。

[1, 2, 3].fill(4)            // [4, 4, 4]
[1, 2, 3].fill(4, 1)         // [1, 4, 4]
[1, 2, 3].fill(4, 1, 2)      // [1, 4, 3]
[1, 2, 3].fill(4, 1, 1)      // [1, 2, 3]
[1, 2, 3].fill(4, -3, -2)    // [4, 2, 3]
[1, 2, 3].fill(4, NaN, NaN)  // [1, 2, 3]
Array(3).fill(4);            // [4, 4, 4]
[].fill.call({length: 3}, 4) // {0: 4, 1: 4, 2: 4, length: 3}

Array.prototype.keys()/values()/entries()

這三個方法用於遍歷數組。它們都返回一個遍歷器對象,可用for…of遍歷,唯一的區別是:keys()是對鍵值的鍵名的遍歷,values()是對鍵值的遍歷,entries()是對鍵值對的遍歷。

for(var index of ['a', 'b'].keys()) {
  console.log(index); // 0 1
}

for(var value of ['a', 'b'].values()) {
  console.log(value); // 'a' 'b'
}

for(var [index, value] of ['a', 'b'].entries()) {
  console.log([index, value]);
  // [0, 'a'] [1, 'b']
}

如果不使用for…of遍歷,可以手動調用遍歷器對象的next方法進行遍歷。

let arr = ['a', 'b', 'c'];
let entries = arr.entries();

console.log(entries.next().value); // [0, 'a']
console.log(entries.next().value); // [1, 'b']
console.log(entries.next().value); // [2, 'c']
console.log(entries.next().value); // undefined

Array.prototype.includes()

該方法返回一個布爾值,表示一個數組中是否存在某個元素。該方法屬於ES7,但是Babel轉碼器已經支持。

[1, 2, 3].includes(2); // true
[1, 2, 3].includes(4); // false
[NaN].includes(NaN); // true

該方法的第二個參數表示搜索的起始位置,默認爲0。如果第二個參數爲負數,則表示倒數的位置,如果這時它大於數組長度(比如第二個參數爲-4,但數組長度爲3),則會重置爲從0開始。

[1, 2, 3].includes(3, 3);  // false
[1, 2, 3].includes(3, -1); // true

該方法類似於使用indexOf()判斷一個元素是否在數組。但是這個方法有兩個好處:

  • 語義更清晰,使用indexOf()需要與-1比較
  • 可以判斷NaN。indexOf()內部使用===判斷相等,而NaN !== NaN

數組的空位

空位表示數組的某個位置沒有任何值。比如,Array構造的函數都是空位(一個參數)。

var arr = new Array(3);
0 in arr; // false
-------------------
0 in [undefined]; //true, 其中0是數組的鍵名,即索引

ES5對空位的處理不一致,大多數情況下忽略空位:

  • forEach()、filter()、every()、some()都會跳過空位
  • map()會掉過空位,但會保留這個值
  • join()和toString()會將空位視爲undefined,而將undefined和null視爲空字符串
  • etc…由於對空位處理非常不同意,所以建議避免空位

數組推導

數組推導提供了簡潔寫法,允許直接通過現有數組生成新數組。爲了讓其支持所有數據結構(內部調用iterator對象),不像現在之調用數組,所以將其推遲到ES7。Babel轉碼器已經支持這個功能。

略。

參考

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array

es6.ruanyifeng.com

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