陣列是從索引 (自然數,從 0 開始) 到任意值的映射。值 (映射的範圍) 稱為陣列的元素。建立陣列最方便的方法是透過陣列文字。此類文字會列舉陣列元素;元素的位置會隱含指定其索引。
在本章中,我將首先介紹基本的陣列機制,例如索引存取和length
屬性,然後再介紹陣列方法。
本節提供陣列的快速概觀。詳細資訊將在後續說明。
作為第一個範例,我們透過陣列文字建立陣列 arr
(請參閱建立陣列),並存取元素 (請參閱陣列索引)
> var arr = [ 'a', 'b', 'c' ]; // array literal > arr[0] // get element 0 'a' > arr[0] = 'x'; // set element 0 > arr [ 'x', 'b', 'c' ]
我們可以使用陣列屬性 length
(請參閱length) 來移除和追加元素:
> var arr = [ 'a', 'b', 'c' ]; > arr.length 3 > arr.length = 2; // remove an element > arr [ 'a', 'b' ] > arr[arr.length] = 'd'; // append an element > arr [ 'a', 'b', 'd' ]
陣列方法 push()
提供另一種追加元素的方式
> var arr = [ 'a', 'b' ]; > arr.push('d') 3 > arr [ 'a', 'b', 'd' ]
ECMAScript 標準將陣列指定為從索引到值的映射 (字典)。換句話說,陣列可能不是連續的,而且可能會有空洞。例如:
> var arr = []; > arr[0] = 'a'; 'a' > arr[2] = 'b'; 'b' > arr [ 'a', , 'b' ]
前述陣列有一個空洞:索引 1 沒有元素。 陣列中的空洞 會更詳細地說明空洞。
請注意,大多數 JavaScript 引擎會在內部最佳化沒有空洞的陣列,並將它們連續儲存。
陣列仍然是物件,而且可以有物件屬性。這些屬性不被視為實際陣列的一部分;換句話說,它們不被視為陣列元素:
> var arr = [ 'a', 'b' ]; > arr.foo = 123; > arr [ 'a', 'b' ] > arr.foo 123
您可以透過陣列文字建立陣列
var
myArray
=
[
'a'
,
'b'
,
'c'
];
陣列中的尾隨逗號會被忽略
> [ 'a', 'b' ].length 2 > [ 'a', 'b', ].length 2 > [ 'a', 'b', ,].length // hole + trailing comma 3
有兩種使用建構函式 Array
的方法:您可以建立具有指定長度的空陣列,或建立元素為指定值的陣列。對於此建構函式,new
是可選的:將其呼叫為一般函式 (不使用 new
) 的效果與將其呼叫為建構函式相同。
具有指定長度的空陣列只會在其中有空洞!因此,使用此版本的建構函式的情況很少:
> var arr = new Array(2); > arr.length 2 > arr // two holes plus trailing comma (ignored!) [ , ,]
某些引擎可能會在您以這種方式呼叫 Array()
時預先配置連續記憶體,這可能會稍微提升效能。不過,請務必確認增加的詳細程度和冗餘是否值得!
這種呼叫 Array
的方式 類似陣列文字:
// The same as ['a', 'b', 'c']:
var
arr1
=
new
Array
(
'a'
,
'b'
,
'c'
);
問題是您無法建立只包含一個數字的陣列,因為這會被解譯為建立一個 length
為該數字的陣列
> new Array(2) // alas, not [ 2 ] [ , ,] > new Array(5.7) // alas, not [ 5.7 ] RangeError: Invalid array length > new Array('abc') // ok [ 'abc' ]
如果您需要多維的元素,您必須巢狀陣列。當您建立此類巢狀陣列時,最內層的陣列可以視需要而擴充。但是,如果您想要直接存取元素,您至少需要建立外層陣列。在以下範例中,我建立一個三乘三的井字遊戲矩陣。矩陣完全填滿資料(與讓列視需要而擴充相反):
// Create the Tic-tac-toe board
var
rows
=
[];
for
(
var
rowCount
=
0
;
rowCount
<
3
;
rowCount
++
)
{
rows
[
rowCount
]
=
[];
for
(
var
colCount
=
0
;
colCount
<
3
;
colCount
++
)
{
rows
[
rowCount
][
colCount
]
=
'.'
;
}
}
// Set an X in the upper right corner
rows
[
0
][
2
]
=
'X'
;
// [row][column]
// Print the board
rows
.
forEach
(
function
(
row
)
{
console
.
log
(
row
.
join
(
' '
));
});
以下是輸出
. . X . . . . . .
我希望範例示範一般情況。很明顯地,如果矩陣很小而且具有固定維度,您可以透過陣列文字設定它
var
rows
=
[
[
'.'
,
'.'
,
'.'
],
[
'.'
,
'.'
,
'.'
],
[
'.'
,
'.'
,
'.'
]
];
當您使用陣列索引時,您必須記住下列限制:
超出範圍的索引會被視為一般屬性金鑰(字串!)。它們不會顯示為陣列元素,而且不會影響屬性 length
。例如
> var arr = []; > arr[-1] = 'a'; > arr [] > arr['-1'] 'a' > arr[4294967296] = 'b'; > arr [] > arr['4294967296'] 'b'
in
運算子 會偵測物件是否具有具有特定金鑰的屬性。但是,它也可以用來判斷陣列中是否存在特定元素索引。例如:
> var arr = [ 'a', , 'b' ]; > 0 in arr true > 1 in arr false > 10 in arr false
除了刪除屬性之外, delete
運算子 也會刪除陣列元素。刪除元素會產生空洞( length
屬性不會更新):
> var arr = [ 'a', 'b' ]; > arr.length 2 > delete arr[1] // does not update length true > arr [ 'a', ] > arr.length 2
您也可以透過減少陣列長度來刪除尾端的陣列元素(有關詳細資料,請參閱 length)。若要移除元素而不產生空洞(也就是後續元素的索引會遞減),請使用 Array.prototype.splice()
(請參閱 新增和移除元素(破壞性))。在此範例中,我們在索引 1 移除兩個元素
> var arr = ['a', 'b', 'c', 'd']; > arr.splice(1, 2) // returns what has been removed [ 'b', 'c' ] > arr [ 'a', 'd' ]
這是進階章節。您通常不需要了解這裡說明的詳細資訊。
陣列索引並非表面上所見。到目前為止,我假裝陣列 索引是數字。而這是 JavaScript 引擎在內部實作陣列的方式。然而,ECMAScript 規範以不同的方式看待索引。改寫 第 15.4 節
P
(字串)是 陣列索引,當且僅當 ToString
(ToUint32(P))
等於 P
且 ToUint32(P)
不等於 232−1。這表示什麼意思,將在稍後說明。
換句話說,在規範的世界中,括號中的所有值都會轉換為字串並解釋為屬性金鑰,甚至是數字。下列互動展示了這一點
> var arr = ['a', 'b']; > arr['0'] 'a' > arr[0] 'a'
要成為陣列索引,屬性金鑰 P
(字串!)必須等於下列運算的結果
P
轉換為數字。
這表示陣列索引必須是 32 位元範圍 0 ≤ i < 232−1 中的字串化整數 i。規範中明確排除了上限(如前所述)。它保留給最大長度。讓我們使用 函式 ToUint32()
從 透過位元運算子取得 32 位元整數 來了解此定義如何運作。
首先,不包含數字的字串總是轉換為 0,字串化後,不等於字串
> ToUint32('xyz') 0 > ToUint32('?@#!') 0
其次,超出範圍的字串化整數也會轉換為完全不同的整數,字串化後,不等於字串
> ToUint32('-1') 4294967295 > Math.pow(2, 32) 4294967296 > ToUint32('4294967296') 0
第三,字串化的非整數數字會轉換為整數,再次地,不同
> ToUint32('1.371') 1
請注意,規範也強制執行陣列索引沒有指數
> ToUint32('1e3') 1000
且沒有前導零
> var arr = ['a', 'b']; > arr['0'] // array index 'a' > arr['00'] // normal property undefined
length
屬性的基本功能是追蹤陣列中最高的索引:
> [ 'a', 'b' ].length 2 > [ 'a', , 'b' ].length 3
因此,length
沒有計算元素的數量,所以你必須自己撰寫函式來執行這項工作。例如
function
countElements
(
arr
)
{
var
elemCount
=
0
;
arr
.
forEach
(
function
()
{
elemCount
++
;
});
return
elemCount
;
}
若要計算元素(非空洞),我們使用 forEach
會略過空洞的事實。以下是互動
> countElements([ 'a', 'b' ]) 2 > countElements([ 'a', , 'b' ]) 2
手動增加陣列長度對陣列的影響非常小;它只會建立空洞:
> var arr = [ 'a', 'b' ]; > arr.length = 3; > arr // one hole at the end [ 'a', 'b', ,]
最後的結果在結尾有兩個逗號,因為尾隨逗號是可選的,因此總是會被忽略。
我們剛剛執行的動作沒有新增任何元素
> countElements(arr) 2
然而,length
屬性會作為指標,顯示插入新元素的位置。例如
> arr.push('c') 4 > arr [ 'a', 'b', , 'c' ]
因此,透過 Array
建構函式設定陣列的初始長度,會建立一個完全空的陣列
> var arr = new Array(2); > arr.length 2 > countElements(arr) 0
如果你減少陣列長度,所有在新長度及以上位置的元素都會被刪除:
> var arr = [ 'a', 'b', 'c' ]; > 1 in arr true > arr[1] 'b' > arr.length = 1; > arr [ 'a' ] > 1 in arr false > arr[1] undefined
如果你將陣列長度設定為 0,它就會變成空的。這允許你為其他人清除陣列。例如:
function
clearArray
(
arr
)
{
arr
.
length
=
0
;
}
以下是互動
> var arr = [ 'a', 'b', 'c' ]; > clearArray(arr) > arr []
不過,請注意,這種方法可能會很慢,因為每個陣列元素都會被明確刪除。諷刺的是,建立一個新的空陣列通常會更快
arr
=
[];
>
var
a1
=
[
1
,
2
,
3
];
>
var
a2
=
a1
;
>
a1
.
length
=
0
;
>
a1
[]
>
a2
[]
相反地,指定一個空陣列不會
>
var
a1
=
[
1
,
2
,
3
];
>
var
a2
=
a1
;
>
a1
=
[];
>
a1
[]
>
a2
[
1
,
2
,
3
]
陣列的最大長度為 232−1:
> var arr1 = new Array(Math.pow(2, 32)); // not ok RangeError: Invalid array length > var arr2 = new Array(Math.pow(2, 32)-1); // ok > arr2.push('x'); RangeError: Invalid array length
陣列是從索引到值的對應。這表示陣列可以有空洞,即小於長度且在陣列中遺失的索引。在其中一個索引讀取元素會傳回 undefined
。
建議你在陣列中避免空洞。JavaScript 對它們的處理不一致(例如,有些方法會忽略它們,有些則不會)。謝天謝地,你通常不需要知道如何處理空洞:它們很少有用,而且會對效能產生負面影響。
你可以透過指定陣列索引來建立空洞:
> var arr = []; > arr[0] = 'a'; > arr[2] = 'c'; > 1 in arr // hole at index 1 false
您也可以透過在陣列字面中省略值來建立洞
> var arr = ['a',,'c']; > 1 in arr // hole at index 1 false
您需要兩個尾隨逗號才能建立一個尾隨洞,因為最後一個逗號總是會被忽略
> [ 'a', ].length 1 > [ 'a', ,].length 2
本節探討洞與元素中的 undefined
之間的差異。由於讀取洞會傳回 undefined
,因此兩者非常相似。
具有洞的陣列稱為 稀疏。 沒有洞的陣列稱為 稠密。稠密陣列是連續的,且每個索引中都有元素,從 0 開始,以 length
− 1 結束。讓我們比較以下兩個陣列,一個稀疏陣列和一個稠密陣列。兩者非常相似:
var
sparse
=
[
,
,
'c'
];
var
dense
=
[
undefined
,
undefined
,
'c'
];
洞幾乎就像在同一個索引中具有元素 undefined
。兩個陣列的長度相同
> sparse.length 3 > dense.length 3
但稀疏陣列在索引 0 處沒有元素
> 0 in sparse false > 0 in dense true
透過 for
進行反覆運算對兩個陣列來說是 相同的:
> for (var i=0; i<sparse.length; i++) console.log(sparse[i]); undefined undefined c > for (var i=0; i<dense.length; i++) console.log(dense[i]); undefined undefined c
透過 forEach
進行反覆運算會略過洞,但不會略過未定義的元素:
> sparse.forEach(function (x) { console.log(x) }); c > dense.forEach(function (x) { console.log(x) }); undefined undefined c
涉及 陣列的一些運算會忽略洞,而另一些運算則會考慮洞。本節說明詳細資訊。
forEach()
會略過 洞:
> ['a',, 'b'].forEach(function (x,i) { console.log(i+'.'+x) }) 0.a 2.b
every()
也會 略過洞(類似地:some()
):
> ['a',, 'b'].every(function (x) { return typeof x === 'string' }) true
map()
會略過,但會保留洞
> ['a',, 'b'].map(function (x,i) { return i+'.'+x }) [ '0.a', , '2.b' ]
filter()
會消除洞:
> ['a',, 'b'].filter(function (x) { return true }) [ 'a', 'b' ]
join()
會將洞、undefined
和 null
轉換為空字串:
> ['a',, 'b'].join('-') 'a--b' > [ 'a', undefined, 'b' ].join('-') 'a--b'
sort()
在排序時會保留洞
> ['a',, 'b'].sort() // length of result is 3 [ 'a', 'b', , ]
apply()
會將每個洞轉換成一個參數,其值為 undefined
。以下互動示範了這一點:函式 f()
會將其參數傳回為陣列。當我們傳遞一個包含三個洞的陣列給 apply()
以呼叫 f()
時,後者會收到三個 undefined
參數
> function f() { return [].slice.call(arguments) } > f.apply(null, [ , , ,]) [ undefined, undefined, undefined ]
這表示我們可以使用 apply()
來建立一個包含 undefined
的陣列:
> Array.apply(null, Array(3)) [ undefined, undefined, undefined ]
apply()
將空陣列中的洞轉換為 undefined
,但無法用於填補任意陣列(可能包含或不包含洞)中的洞。例如,任意陣列 [2]
> Array.apply(null, [2]) [ , ,]
陣列不包含任何洞,因此 apply()
應傳回相同的陣列。相反地,它傳回一個長度為 2 的空陣列(僅包含兩個洞)。這是因為 Array()
將單一數字解譯為陣列長度,而不是陣列元素。
正如我們所見,filter()
會移除洞:
> ['a',, 'b'].filter(function (x) { return true }) [ 'a', 'b' ]
使用自訂函式將任意陣列中的洞轉換為 undefined
function
convertHolesToUndefineds
(
arr
)
{
var
result
=
[];
for
(
var
i
=
0
;
i
<
arr
.
length
;
i
++
)
{
result
[
i
]
=
arr
[
i
];
}
return
result
;
}
使用函式
> convertHolesToUndefineds(['a',, 'b']) [ 'a', undefined, 'b' ]
Array.isArray(obj)
obj
是陣列,則傳回 true
。它正確處理跨越 領域(視窗或框架)的物件,與 instanceof
相反(請參閱 陷阱:跨越領域(框架或視窗))。
Array.prototype.shift()
移除 索引 0 處的元素並傳回它。後續元素的索引會遞減 1:
> var arr = [ 'a', 'b' ]; > arr.shift() 'a' > arr [ 'b' ]
Array.prototype.unshift(elem1?, elem2?, ...)
> var arr = [ 'c', 'd' ]; > arr.unshift('a', 'b') 4 > arr [ 'a', 'b', 'c', 'd' ]
Array.prototype.pop()
移除陣列的最後一個元素並傳回:
> var arr = [ 'a', 'b' ]; > arr.pop() 'b' > arr [ 'a' ]
Array.prototype.push(elem1?, elem2?, ...)
將指定的元素加入陣列的尾端。傳回新的長度:
> var arr = [ 'a', 'b' ]; > arr.push('c', 'd') 4 > arr [ 'a', 'b', 'c', 'd' ]
apply()
(請參閱 Function.prototype.apply(thisValue, argArray))讓您可以破壞性地將陣列 arr2
附加至另一個陣列 arr1
:
> var arr1 = [ 'a', 'b' ]; > var arr2 = [ 'c', 'd' ]; > Array.prototype.push.apply(arr1, arr2) 4 > arr1 [ 'a', 'b', 'c', 'd' ]
Array.prototype.splice(start, deleteCount?, elem1?, elem2?, ...)
從 start
開始,移除 deleteCount
個元素並插入指定的元素。換句話說,您會用 elem1
、elem2
等取代位置 start
的 deleteCount
個元素。此方法會傳回已移除的元素:
> var arr = [ 'a', 'b', 'c', 'd' ]; > arr.splice(1, 2, 'X'); [ 'b', 'c' ] > arr [ 'a', 'X', 'd' ]
特殊參數值
start
可以為負數,如果是這樣,會將其加到長度以決定開始索引。因此,-1
指的是最後一個元素,依此類推。
deleteCount
為選用參數。如果省略(以及所有後續參數),則會移除索引 start
及其後的所有元素。
在此範例中,我們會移除倒數第二個索引及其後的所有元素
> var arr = [ 'a', 'b', 'c', 'd' ]; > arr.splice(-2) [ 'c', 'd' ] > arr [ 'a', 'b' ]
這些方法也是破壞性的
Array.prototype.reverse()
> var arr = [ 'a', 'b', 'c' ]; > arr.reverse() [ 'c', 'b', 'a' ] > arr // reversing happened in place [ 'c', 'b', 'a' ]
Array.prototype.sort(compareFunction?)
排序陣列並傳回:
> var arr = ['banana', 'apple', 'pear', 'orange']; > arr.sort() [ 'apple', 'banana', 'orange', 'pear' ] > arr // sorting happened in place [ 'apple', 'banana', 'orange', 'pear' ]
請記住,排序會將值轉換為字串後再進行比較,這表示數字並非以數字方式排序
> [-1, -20, 7, 50].sort() [ -1, -20, 50, 7 ]
您可以透過提供選用參數 compareFunction
來修正這個問題,此參數會控制排序方式。其簽章如下
function
compareFunction
(
a
,
b
)
此函式會比較 a
和 b
,並傳回
-1
),如果 a
小於 b
a
等於 b
1
),如果 a
大於 b
對於數字,您可以直接傳回 a-b
,但這可能會導致數字溢位。為了防止這種情況發生,您需要更冗長的程式碼:
function
compareCanonically
(
a
,
b
)
{
if
(
a
<
b
)
{
return
-
1
;
}
else
if
(
a
>
b
)
{
return
1
;
}
else
{
return
0
;
}
}
我不喜歡巢狀條件運算子。但在這種情況下,程式碼簡潔許多,我忍不住推薦它:
function
compareCanonically
(
a
,
b
)
{
return
a
<
b
?
-
1
:
(
a
>
b
?
1
:
0
);
}
使用函式
> [-1, -20, 7, 50].sort(compareCanonically) [ -20, -1, 7, 50 ]
對於字串,您可以使用 String.prototype.localeCompare
(請參閱比較字串)
> ['c', 'a', 'b'].sort(function (a,b) { return a.localeCompare(b) }) [ 'a', 'b', 'c' ]
參數 compareFunction
也可用於排序物件:
var
arr
=
[
{
name
:
'Tarzan'
},
{
name
:
'Cheeta'
},
{
name
:
'Jane'
}
];
function
compareNames
(
a
,
b
)
{
return
a
.
name
.
localeCompare
(
b
.
name
);
}
使用 compareNames
作為比較函式,arr
會依據 name
進行排序
> arr.sort(compareNames) [ { name: 'Cheeta' }, { name: 'Jane' }, { name: 'Tarzan' } ]
下列方法對陣列執行各種非破壞性操作:
Array.prototype.concat(arr1?, arr2?, ...)
建立一個新陣列,其中包含接收者陣列的所有元素,接著是陣列 arr1
的所有元素,依此類推。如果其中一個參數不是陣列,則會將其作為元素新增到結果中(例如,這裡的第一個參數 'c'
):
> var arr = [ 'a', 'b' ]; > arr.concat('c', ['d', 'e']) [ 'a', 'b', 'c', 'd', 'e' ]
呼叫 concat()
的陣列不會改變
> arr [ 'a', 'b' ]
Array.prototype.slice(begin?, end?)
將陣列元素複製到一個新陣列中,從 begin
開始,直到(不包含)end
處的元素:
> [ 'a', 'b', 'c', 'd' ].slice(1, 3) [ 'b', 'c' ]
如果沒有 end
,則會使用陣列長度
> [ 'a', 'b', 'c', 'd' ].slice(1) [ 'b', 'c', 'd' ]
如果兩個索引都遺失,則會複製陣列
> [ 'a', 'b', 'c', 'd' ].slice() [ 'a', 'b', 'c', 'd' ]
如果任一索引為負數,則會將陣列長度新增到該索引。因此,-1
指的是最後一個元素,依此類推
> [ 'a', 'b', 'c', 'd' ].slice(1, -1) [ 'b', 'c' ] > [ 'a', 'b', 'c', 'd' ].slice(-2) [ 'c', 'd' ]
Array.prototype.join(separator?)
透過對所有陣列元素套用 toString()
,並將字串置於結果之間的 separator
中,來建立一個字串。如果省略 separator
,則會使用 ','
:
> [3, 4, 5].join('-') '3-4-5' > [3, 4, 5].join() '3,4,5' > [3, 4, 5].join('') '345'
join()
會將 undefined
和 null
轉換為空字串
> [undefined, null].join('#') '#'
陣列中的空洞也會轉換為空字串
> ['a',, 'b'].join('-') 'a--b'
下列方法用於在陣列中搜尋值:
Array.prototype.indexOf(searchValue, startIndex?)
從startIndex
開始,在陣列中搜尋searchValue
。它會傳回第一次出現的索引,如果沒有找到則傳回–1。如果startIndex
為負數,則會加上陣列長度;如果沒有指定,則會搜尋整個陣列:
> [ 3, 1, 17, 1, 4 ].indexOf(1) 1 > [ 3, 1, 17, 1, 4 ].indexOf(1, 2) 3
搜尋時會使用嚴格相等(請參閱相等運算子:=== 與 ==),這表示indexOf()
無法找到NaN
:
> [NaN].indexOf(NaN) -1
Array.prototype.lastIndexOf(searchElement, startIndex?)
從startIndex
開始,向後在陣列中搜尋searchElement
。它會傳回第一次出現的索引,如果沒有找到則傳回–1。如果startIndex
為負數,則會加上陣列長度;如果沒有指定,則會搜尋整個陣列。搜尋時會使用嚴格相等(請參閱相等運算子:=== 與 ==)
> [ 3, 1, 17, 1, 4 ].lastIndexOf(1) 3 > [ 3, 1, 17, 1, 4 ].lastIndexOf(1, -3) 1
反覆運算方法使用函式來反覆運算陣列。我將反覆運算方法分為三種類型,所有類型都是非破壞性的:檢查方法主要用於觀察陣列的內容;轉換方法從接收者衍生出一個新陣列;簡化方法根據接收者的元素計算結果。
本節中描述的每種方法如下所示:
arr
.
examinationMethod
(
callback
,
thisValue
?
)
此類方法會採用下列參數
callback
是第一個參數,它會呼叫的函式。根據檢查方法的不同,callback 會傳回布林值或不傳回任何值。其簽章如下
function
callback
(
element
,
index
,
array
)
element
是陣列元素,供callback
處理,index
是元素的索引,而array
則是examinationMethod
被呼叫的陣列。
thisValue
可讓您設定callback
內部this
的值。
以下是簽章剛才描述的檢查方法:
Array.prototype.forEach(callback, thisValue?)
反覆運算陣列中的元素
var
arr
=
[
'apple'
,
'pear'
,
'orange'
];
arr
.
forEach
(
function
(
elem
)
{
console
.
log
(
elem
);
});
Array.prototype.every(callback, thisValue?)
這個範例會檢查陣列中的每個數字是否都是偶數
> function isEven(x) { return x % 2 === 0 } > [ 2, 4, 6 ].every(isEven) true > [ 2, 3, 4 ].every(isEven) false
如果陣列是空的,結果會是 true
(而且不會呼叫 callback
)
> [].every(function () { throw new Error() }) true
Array.prototype.some(callback, thisValue?)
這個範例會檢查陣列中是否有偶數
> function isEven(x) { return x % 2 === 0 } > [ 1, 3, 5 ].some(isEven) false > [ 1, 2, 3 ].some(isEven) true
如果陣列是空的,結果會是 false
(而且不會呼叫 callback
)
> [].some(function () { throw new Error() }) false
forEach()
的一個潛在陷阱是,它不支援 break
或類似用於提早中止迴圈的語法。如果你需要這麼做,可以使用 some()
function
breakAtEmptyString
(
strArr
)
{
strArr
.
some
(
function
(
elem
)
{
if
(
elem
.
length
===
0
)
{
return
true
;
// break
}
console
.
log
(
elem
);
// implicit: return undefined (interpreted as false)
});
}
some()
會在發生中斷時傳回 true
,否則傳回 false
。這能讓你根據反覆運算是否成功完成而做出不同的反應(這在使用 for
迴圈時會有點棘手)。
轉換 方法會取得輸入陣列並產生輸出陣列,而 callback 則控制輸出的產生方式。callback 的簽章與檢查相同:
function
callback
(
element
,
index
,
array
)
Array.prototype.map(callback, thisValue?)
每個輸出陣列元素都是將 callback
套用至輸入元素的結果。例如
> [ 1, 2, 3 ].map(function (x) { return 2 * x }) [ 2, 4, 6 ]
Array.prototype.filter(callback, thisValue?)
輸出陣列 僅包含那些輸入元素,其中 callback
傳回 true
。例如:
> [ 1, 0, 3, 0 ].filter(function (x) { return x !== 0 }) [ 1, 3 ]
對於簡化,callback 具有不同的簽章:
function
callback
(
previousValue
,
currentElement
,
currentIndex
,
array
)
參數 previousValue
是 callback 先前傳回的值。當 callback 第一次呼叫時,有兩種可能性(說明是針對 Array.prototype.reduce()
;括號中提到與 reduceRight()
的差異)
initialValue
。然後 previousValue
是 initialValue
,而 currentElement
是第一個陣列元素(reduceRight
:最後一個陣列元素)。
initialValue
。然後 previousValue
是第一個陣列元素,而 currentElement
是第二個陣列元素(reduceRight
:最後一個陣列元素和倒數第二個陣列元素)。
有兩種簡化方法
Array.prototype.reduce(callback, initialValue?)
從左到右反覆運算,並呼叫之前草擬的 callback。此方法的結果是 callback 傳回的最後一個值。此範例計算所有陣列元素的總和:
function
add
(
prev
,
cur
)
{
return
prev
+
cur
;
}
console
.
log
([
10
,
3
,
-
1
].
reduce
(
add
));
// 12
如果您對單一元素的陣列呼叫 reduce
,則會傳回該元素
> [7].reduce(add) 7
如果您對空陣列呼叫 reduce
,則必須指定 initialValue
,否則會產生例外狀況
> [].reduce(add) TypeError: Reduce of empty array with no initial value > [].reduce(add, 123) 123
Array.prototype.reduceRight(callback, initialValue?)
reduce()
相同,但從右到左反覆運算。 在許多函式程式語言中,reduce
稱為 fold
或 foldl
(左折疊),而 reduceRight
稱為 foldr
(右折疊)。
檢視 reduce
方法的另一種方式是,它實作 n 元運算子 OP
OP1≤i≤n
xi
透過連續應用二元運算子 op2
(...(x1 op2
x2) op2
...) op2
xn
這正是前一個程式碼範例所做的:我們透過 JavaScript 的二元加法運算子實作陣列的 n 元加法運算子。
讓我們透過以下函式來檢視兩個反覆運算方向,作為範例
function
printArgs
(
prev
,
cur
,
i
)
{
console
.
log
(
'prev:'
+
prev
+
', cur:'
+
cur
+
', i:'
+
i
);
return
prev
+
cur
;
}
正如預期,reduce()
從左到右反覆運算
> ['a', 'b', 'c'].reduce(printArgs) prev:a, cur:b, i:1 prev:ab, cur:c, i:2 'abc' > ['a', 'b', 'c'].reduce(printArgs, 'x') prev:x, cur:a, i:0 prev:xa, cur:b, i:1 prev:xab, cur:c, i:2 'xabc'
而 reduceRight()
從右到左反覆運算
> ['a', 'b', 'c'].reduceRight(printArgs) prev:c, cur:b, i:1 prev:cb, cur:a, i:0 'cba' > ['a', 'b', 'c'].reduceRight(printArgs, 'x') prev:x, cur:c, i:2 prev:xc, cur:b, i:1 prev:xcb, cur:a, i:0 'xcba'
JavaScript 中的某些物件看起來像陣列,但實際上並非陣列。這通常表示它們有索引存取和 length
屬性,但沒有任何陣列方法。範例包括特殊變數 arguments
、DOM 節點清單和字串。 類陣列物件和一般方法 提供處理類陣列物件的提示。
一個簡單的 for
迴圈(請參閱 for)
for
(
var
i
=
0
;
i
<
arr
.
length
;
i
++
)
{
console
.
log
(
arr
[
i
]);
}
其中一個陣列反覆運算方法(請參閱 反覆運算(非破壞性))。例如,forEach()
arr
.
forEach
(
function
(
elem
)
{
console
.
log
(
elem
);
});
不要使用 for-in
迴圈(請參閱 for-in)來反覆運算陣列。它會反覆運算索引,而非值。而且在這樣做的同時,它會包含一般屬性的金鑰,包括繼承的屬性。