標籤:block ... global 填充 枚舉 參數 second eve oba
JavaScript中的數組建立
數組是一個包含了對象或原始類型的有序集合。很難想象一個不使用數組的程式會是什麼樣。
以下是幾種運算元組的方式:
初始化數組並設定初始值
通過索引訪問數組元素
添加新元素
刪除現有元素
本文涵蓋了數組的初始化以及設定初始值的操作。在JavaScript中要做到這一點的基本方法是使用數組字面量,例如[1, 5, 8]
或是數組構造器new Array (1, 5, 8)
。
除了手動枚舉之外,JavaScript還提供了更有趣更直接的數組建立方式。讓我一起看看在JavaScript中初始化數組的一般情境和進階情境吧。
1. 數組字面量
數組字面量由一組包裹在方括弧[
]
之間的逗號分隔的元素element1, element2, ..., elementN
組成。
讓我們看幾個數組字面量的例子:
在JS Bin中查看
let numbers = [1, 5, 7, 8];let planets = ['Earth', 'Mercury', 'Jupiter'];
數組字面量可以包含任意類型的元素,包括null
, undefined
, 原始類型以及對象:
在JS Bin中查看
let mixed = [1, 'Earth', null, NaN, undefined, ['Mars']];
1.1 數組字面量中的逗號
逗號,
用來分隔數組字面量中的元素。基於逗號的位置或是逗號之間元素的缺失的情況,不同結構的數組會被建立。
讓我們詳細看一看現有的三種情況。
第一種情況:普通的數組字面量
通常情況是在任何一對逗號之間都有一個元素並且數組字面量不以逗號開始或結尾。這是推薦的使用逗號分隔手動初始化數組的方式:
在JS Bin中查看
let items = ['first', 'second', 'third'];items; // => ['first', 'second', 'third']
items
是由2個逗號分隔的3個元素建立的。
在這個例子中item
是一個密集數組,因為它的元素有著連續的索引(或者簡單來說數組中沒有空洞)。
大多數時候,你會使用這種方式初始化數組。
第二種情況: 在數組末尾的一個無用逗號
第二種情況和第一種情況類似,只不過在最後一個逗號之後沒有指定元素。這種情況中,最後一個逗號會被JavaScript忽略:
在JS Bin中查看
let items = ['first', 'second', 'third', ];items; // => ['first', 'second', 'third']
在元素‘third‘
之後指定的一個逗號,它是數組中的最後一個逗號並且在那之後沒有任何元素。這個末尾的逗號是無用的,意味著它對新建立的數組沒有任何影響。
這種情況下JavaScript也會建立一個密集數組。
第三種情況: 逗號之間沒有元素
第三種情況發生在當一對逗號之間沒有指定元素或是數組字面量以一個逗號開始時。
這會建立一個稀疏數組:一個其元素索引不連續的集合(換句話說數組中存在空洞)。
下面的數組字面量以逗號開始,建立了一個稀疏數組:
在JS Bin中查看
let items = [, 'first', 'second', 'third'];items; // => [<1 empty slot>, 'first', 'second', 'third']items[0]; // => undefineditems[1]; // => 'first'items.length; // => 4
數組字面量[, ...]
以逗號開始。結果是items
是一個稀疏數組,在索引0
的位置是一個空slot。訪問空slot items[0]
會得到undefined
。
區分一個空slot和一個值是undefined
的元素是很重要的。通過索引訪問這種類型的元素時都會得到undefined
,這使得區分它們變得很棘手。
空slot意味著數組在某個索引位置上沒有元素(index in array
返回false
),這與一個值是undefined
的元素(index in array
返回true
)是不同的。
需要注意的是空slot在Firefox的控制台會被顯示為<1 empty slot>
,這是展示空slot的正確方法。Chrome的控制台會展示undefined x 1
。其它瀏覽器的控制台只會簡單的展示undefined
。
當數組字面量的兩個逗號之間沒有元素時也會建立一個稀疏數組:
在JS Bin中查看
let items = ['first', , 'second', 'third'];items; // => ['first', <1 empty slot> ,'second', 'third']items[0]; // => 'first'items[1]; // => undefineditems.length; // => 4
數組字面量包含了中間沒有元素的逗號:[... , , ...]
。這樣item
成了一個索引1
處是一個空slot的稀疏數組。訪問空slot items[1]
會得到undefined
。
通常你應該避免這種會建立稀疏數組的使用方式。同時你也應該儘可能的不去操作稀疏數組。
在一個數組字面量中刪除或是添加元素時你可能會在不經意間建立一個稀疏數組。因此在修改之後切記仔細檢查。
1.2 spread運算子帶來的改善
ECMAScript 6中引入的spread運算子改善了使用其它數組中的元素初始新數組這一操作。
在很多情境下spread運算子都可以使數組建立變得更簡單。方法就是在數組字面量中把...
作為源數組的首碼,然後源數組中的元素就被包括到新建立的數組中了。就這麼簡單。
下面的數組字面量在建立時使用了spread運算子:
在JS Bin中查看
let source = ['second', 'third'];let items = ['first', ...source];items; // => ['first', 'second', 'third']
數組字面量[‘First‘, ...source]
表示‘First‘
會被作為數組中的第一個元素。剩餘的元素則是通過spread運算子從source
數組取得。
常規的元素枚舉方式可以和spread運算子可以不受限制的組合在一起。
在JS Bin中查看
let odds = [1, 3, 5];let evens = [4, 6];let zero = 0;let negative = -1;let items = [...odds, zero, ...evens, negative];items; // => [1, 3, 5, 0, 4, 6, -1]
建立items
時使用一個組合了普通變數zero
和negative
以及前置spread運算子的源數組...odds
和...evens
的集合。
由於spread運算子接收的是普通的可迭代對象(數組預設就是可迭代的),這使得自訂的初始化成為可能。
一個產生器函數也會返回一個可迭代的產生器對象,因此你可以利用產生器的靈活性來建立數組。
讓我們建立一個第一個參數代表元素值第二個參數代表元素數量的產生器函數。然後使用它和spread運算子以及數組字面量來初始化新數組:
在JS Bin中查看
function* elements(element, length) { let index = 0; while (length > index++) { yield element; }}[...elements(0, 5)]; // => [0, 0, 0, 0, 0][...elements('hi', 2)]; // => ['hi', 'hi']
每次執行elements(element, length)
時都會建立一個產生器對象。spread運算子會利用該產生器對象來初始化數組。
[...elements(0, 5)]
會建立一個有5個0的數組。而[...elements(‘hi‘, 2)]
會建立一個有兩個字串‘h1‘
的數組。
2. 數組構造器
JavaScript中的數組是一個對象。和任何對象一樣,它有一個可以用來建立新執行個體的構造器函數Array
。讓我們看一個例子:
在JS Bin中查看
// 構造器調用let arrayConstr = new Array(1, 5);arrayConstr; // => [1, 5]typeof arrayConstr; // => 'object'arrayConstr.constructor === Array; // => true// 數組字面量let arrayLiteral = [1, 5];arrayLiteral; // => [1, 5]typeof arrayLiteral; // => 'object'arrayLiteral.constructor === Array; // => true
arrayConstr
和arrayLiteral
都是數組執行個體,它們的構造器都是Array
。對象arrayConstr
是通過構造器調用建立的:new Array(1, 5)
。
你也可以像調用普通函數那樣通過Array來建立數組執行個體:Array(1, 5)
。
你應該更傾向於使用字面量[item1, item2, ..., itemN]
而不是構造器new Array(item1, item2, ..., itemN)
來建立數組。主要原因是數組字面量的寫法更短,更簡單。還有一個原因就是數組構造器在第一個參數是不同類型的值時,產生的怪異行為。
讓我們看看Array
使如何根據第一個參數的類型以及參數的個數來建立數組執行個體的吧。
2.1 數實值型別的參數下建立稀疏數組
當數組構造器new Array(numberArg)
以一個單一的數實值型別的參數調用時,JavaScript會建立一個帶有參數指定的個數的空slot的稀疏數組。
看一個例子:
在JS Bin中查看
let items = new Array(3);items; // => [<3 empty slots>]items.length; // => 3
new Array(3)
是一個帶有單一參數3
的構造器調用。一個長度為3
的稀疏數組items
被建立了,但實際上它並不包含任何元素而只是有幾個空slot。
這種建立數組的方式本身並沒有什麼價值。然而把它和一些靜態方法組合起來用於建立指定長度的數組並填充產生的元素時卻是有用的。
2.2 枚舉元素
如果調用Array
構造器時傳入了一個參數列表而不是單個數字,那麼這些參數就會成為數組的元素。
這種方式和數組字面量的方式幾乎一樣,只不過是在一個構造器調用中而已。
下面的例子建立了一個數組:
let items = new Array('first', 'second', 'third');items; // => ['first', 'second', 'third']
new Array(‘first‘, ‘second‘, ‘third‘)
使用參數中的元素建立了一個數組。
由於spread運算子的靈活性,在構造器調用中使用來自其它數組的元素也是可行的:
在JS Bin中查看
let source = new Array('second', 'third');let items = new Array('first', ...source);items; // => ['first', 'second', 'third']
new Array(‘First‘, ...source)
建立數組時使用了‘First‘
元素以及source
數組中的所有元素。
無論哪種方式,你都應該傾向於使用數組字面量,因為它更簡單直接。
2.3 有用的靜態方法
當讀到關於通過在構造器調用中傳入一個數字來建立稀疏數組的部分時你可能好奇這有什麼實際的用處。
ECMAScript 6增加了一些有用的方法如Array.prototype.fill()
和Array.from()
。這兩個方法都可以用來填充一個稀疏數組中的空slot。
讓我使用fill()
方法來建立一個包含5個0的數組:
在JS Bin中查看
let zeros = new Array(5).fill(0);zeros; // => [0, 0, 0, 0, 0]
new Array(5)
建立了一個有5個空slot的稀疏數組。接著fill(0)
方法用0
填充了空slot。
靜態方法Array.from()
則有著更寬的使用情境。像上邊的例子一樣,讓我們建立一個包含5個0的數組:
在JS Bin中查看
let zeros = Array.from(new Array(5), () => 0);zeros; // => [0, 0, 0, 0, 0]
一個通過new Array(5)
建立的長度為5
的稀疏組數作為參數被傳遞給Array.from()
。第二個參數作為一個返回0
的映射函數。
共執行了5
次迭代,每次迭代中箭頭函數的傳回值被用作數組的元素。
由於在每次迭代中都會執行映射函數,因此動態建立數組元素是可行的。讓我們建立一個包含1
到5
的數組:
在JS Bin中查看
let items = Array.from(new Array(5), (item, index) => index + 1);items; // => [1, 2, 3, 4, 5]
映射函數被調用時會傳入兩個參數:當前的item
以及當前迭代的index
。索引參數被用來產生元素:index + 1
。
Array.from()
的第一個參數可以接受任何可迭代對象,這使得它更有價值。
讓我們使用一個產生器對象建立一個遞增的數字列表:
在JS Bin中查看
function* generate(max) { let count = 0; while (max > count++) { yield count; }}let items = Array.from(generate(5));items; // => [1, 2, 3, 4, 5]let itemsSpread = [...generate(5)];itemsSpread; // => [1, 2, 3, 4, 5]
generate(max)
是一個產生器函數,它會產生從一串從1
到max
的數字。
Array.from(generate(5))
使用一個產生器對象作為參數建立了一個包含1
到5
數位數組。
使用spread運算子[...generate(5)]
和數組字面量可以達到同樣的目的。
3. 總結
數組初始化是操作集合時的常見操作。JavaScript提供了多種方法以及靈活性來實現該目的。
數組構造器的行為在很多情況下會讓你感到意外。因此數組字面量是初始化數組執行個體更好,更簡單的方式。
當數組需要根據基於每個迭代元素的計算進行初始化時,Array.from()
是一個不錯的選擇。
如果數組元素需要被填充為同一個值,使用Array.prototype.fill()
和new Array(length)
的組合。
不要低估可迭代對象和產生器函數的能力,它們可以和spread運算子組合起來使用在數組字面量或是Array.from()
中。
本文轉載自:眾成翻譯
譯者:loveky
連結:http://www.zcfy.cc/article/713
原文:http://rainsoft.io/power-up-the-array-creation-in-javascript/
JavaScript中的數組建立