首頁  >  文章  >  web前端  >  ECMAScript 6即將帶給我們新的陣列操作方法前瞻_javascript技巧

ECMAScript 6即將帶給我們新的陣列操作方法前瞻_javascript技巧

WBOY
WBOY原創
2016-05-16 16:22:061224瀏覽

本文介紹ECMAScript 6即將帶給我們新的陣列操作方法,以及在如何在現有瀏覽器應用這些新的陣列特性。

Note: 我將使用交替使用建構器(constructor)和類別(class)兩個術語。

類別方法
數組(Array)本身所擁有的方法。

Array.from(arrayLike, mapFunc?, thisArg?)

Array.from()的基本功能是,轉換兩種類型的物件成數組。

類別數組物件(Array-like objects)

該類別物件有長度與索引的屬性。 DOM操作符的結果即屬於該類,如document.getElementsByClassName()。

可迭代物件(Iterable objects)

這類物件在取值時,每次只能取一個元素。數組是可迭代的,就如ECMAScript中新的數組結構,映射(Map)和集(Set)。

以下程式碼是轉換類別陣列物件到陣列的範例:

複製程式碼 程式碼如下:

let lis = document.querySelectorAll('ul.fancy li');
Array.from(lis).forEach(function (li) {
  console.log(node);
});

querySelectorAll()的結果不是一個數組,也不會有forEach()這個方法。這就是我們需要在使用這個方法之前,將它轉換成陣列的原因。

透過Array.from()使用Mapping
Array.from()同樣也是一個泛型使用map()的替代選擇。

複製程式碼 程式碼如下:

let spans = document.querySelectorAll('span.name');
// map(), generically:
let names1 = Array.prototype.map.call(spans, s => s.textContent);
// Array.from():
let names2 = Array.from(spans, s => s.textContent);

兩個方法中的第二個參數,都是箭頭函數(arrow function)。
在這個範例中,document.querySelectorAll()的結果又是一個類別數組對象,而非數組。這就是我們不能直接呼叫map()的原因。在第一個範例中,為了使用forEach(),我們將類別數組物件轉換成了陣列。這裡我們透過泛型方法和兩個參數版本的Array.from(),而省去了中間步驟。

Holes
Array.from()會忽略陣列裡缺少的元素 - 洞(holes),它會以未定義的元素(undefined elements)進行對待。

複製程式碼 程式碼如下:

> Array.from([0,,2])
[ 0, undefined, 2 ]

這意味著,你可以使用Array.from()來建立或填滿一個陣列:

複製程式碼 程式碼如下:

> Array.from(new Array(5), () => 'a')
[ 'a', 'a', 'a', 'a', 'a' ]
> Array.from(new Array(5), (x,i) => i)
[ 0, 1, 2, 3, 4 ]

如果你想用一個固定的值去填充一個數組,那麼Array.prototype.fill()(請看下文)將會是更好的選擇。第一個即是以上範例的兩種方式。

在陣列(Array)子類別中的from()
另一個Array.from()的使用場景是,轉換類別陣列物件或可迭代物件到一個陣列(Array)子類別的一個實例。如你建立了一個Array的子​​類別MyArray,想將這類物件轉換成MyArray的一個實例,你就可以簡單地使用MyArray.from()。可以這樣使用的原因是,在ECMAScript 6中構造器(constructors)會繼承下去(父類別構造器是它子類別構造器的原型(prototype))。

複製程式碼 程式碼如下:

class MyArray extends Array {
  ...
}
let instanceOfMyArray = MyArray.from(anIterable);

你可以將此函數與映射(mapping)結合起來,在一個你控制結果建構器的地方完成映射操作(map operation):

複製程式碼 程式碼如下:

// from() – determine the result's constructor via the receiver
// (in this case, MyArray)
let instanceOfMyArray = MyArray.from([1, 2, 3], x => x * x);
// map(): the result is always an instance of Array
let instanceOfArray   = [1, 2, 3].map(x => x * x);
Array.of(...items)

如果你想將一組值轉換成一個數組,你應該使用數組來源文字(array literal)。特別是只有一個值且還是數字的時候,數組的構造器便罷工了。更多資訊請參考。

複製程式碼 程式碼如下:

> new Array(3, 11, 8)
[ 3, 11, 8 ]
> new Array(3)
[ , ,  ,]
> new Array(3.1)
RangeError: Invalid array length

便如果要將一組值轉換成數字子構造器(sub-constructor)的一個實例,我們該怎麼做呢?這就是Array.of()存在的價值(記住,陣列子建構器會繼承所有的陣列方法,當然也包括of())。

複製程式碼 程式碼如下:

class MyArray extends Array {
  ...
}
console.log(MyArray.of(3, 11, 8) instanceof MyArray); // true
console.log(MyArray.of(3).length === 1); // true

把值包裹嵌套在陣列裡,Array.of()會相當方便,而不會有Array()一樣怪異的處理方式。但也要注意Array.prototype.map(),此處有一個坑:

複製程式碼 程式碼如下:

> ['a', 'b'].map(Array.of)
[ [ 'a', 0, [ 'a', 'b' ] ],
[ 'b', 1, [ 'a', 'b' ] ] ]
> ['a', 'b'].map(x => Array.of(x)) // better
[ [ 'a' ], [ 'b' ] ]
> ['a', 'b'].map(x => [x]) // best (in this case)
[ [ 'a' ], [ 'b' ] ]

如你所看,map()會傳遞三個參數到它的回呼裡面。最後兩個又是常被忽略的(詳細)。

原型方法(Prototype methods)
數組的實例會有很多新的方法可用。

數組裡的迭代(Iterating over arrays)

以下的方法,會幫助完成在陣列裡的迭代:

複製程式碼 程式碼如下:

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

以上的每一個方法都會傳回一串值,卻不會以一個陣列傳回。它們會通過迭代器,一個接一個的顯示。讓我們來看一個範例(我將使用Array.from()將迭代器的內容放在陣列中):

複製程式碼 程式碼如下:

> Array.from([ 'a', 'b' ].keys())
[ 0, 1 ]
> Array.from([ 'a', 'b' ].values())
[ 'a', 'b' ]
> Array.from([ 'a', 'b' ].entries())
[ [ 0, 'a' ],
[ 1, 'b' ] ]

你可以結合entries()和ECMAScript 6中的for-of循環,方便地將迭代物件拆解成key-value對:

複製程式碼 程式碼如下:

for (let [index, elem] of ['a', 'b'].entries()) {
  console.log(index, elem);
}

Note: 這段程式碼已經可以在最新的Firefox瀏覽器裡運作了。 t Firefox.

找出陣列元素

Array.prototype.find(predicate, thisArg?) 會傳回滿足回呼函數的第一個元素。如果沒有任何一個元素滿足條件,它會回傳undefined。如:

複製程式碼 程式碼如下:

> [6, -5, 8].find(x => x -5
> [6, 5, 8].find(x => x undefined
Array.prototype.findIndex(predicate, thisArg?)

會傳回滿足回呼函數的第一個元素的索引。如果找不任何滿足的元素,則回傳-1。如:

複製程式碼 程式碼如下:

> [6, -5, 8].findIndex(x => x 1
> [6, 5, 8].findIndex(x => x -1

兩個find*方法都會忽略洞(holes),也就是不會專注在undefined的元素。回呼的完成函數簽名是:

predicate(element, index, array)
透過findIndex()找NaN

Array.prototype.indexOf()有一個大家所熟知的限制,那就是不能找NaN。因為它用恆等(===)找出匹配元素:

複製程式碼 程式碼如下:

> [NaN].indexOf(NaN)
-1

使用findIndex(),你就可以使用Object.is(),這就不會產生這樣的問題:

複製程式碼 程式碼如下:

> [NaN].findIndex(y => Object.is(NaN, y))
0

你同樣也可以採用更通用的方式,建立一個幫助函數elemIs():

複製程式碼 程式碼如下:

> function elemIs(x) { return Object.is.bind(Object, x) }
> [NaN].findIndex(elemIs(NaN))
0
Array.prototype.fill(value, start?, end?)

用所給的數值,填入一個陣列:

複製程式碼 程式碼如下:

> ['a', 'b', 'c'].fill(7)
[ 7, 7, 7 ]

洞(Holes)也不會有任何的特殊對待:

複製程式碼 程式碼如下:

> new Array(3).fill(7)
[ 7, 7, 7 ]

你也可以限制你填滿的起始與結束:

複製程式碼 程式碼如下:

> ['a', 'b', 'c'].fill(7, 1, 2)
[ 'a', 7, 'c' ]

什麼時候可以使用新的陣列方法?
有一些方法已經可以在瀏覽器裡使用了。

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn