數字為特性的陣列
July 23, 2022陣列是記憶體中線性的連續資料,不過在 JavaScript,是以物件來模擬出相似的操作外觀。
建構陣列
如果要在 JavaScript 中建立所謂的陣列,可以使用 Array
建構出實例。例如:
> var array1 = new Array();
undefined
> array1.length;
0
> var array2 = new Array(10);
undefined
> array2.length;
10
> var array3 = new Array(10, 20, 30);
undefined
> array3.length;
3
>
上面示範了三種 Array
實例建構的方式,第一種方式建構出沒有任何元素的陣列,第二種方式建構出長度為 10 的陣列,每個索引位置(0 到 9)都是 undefined
,第三種方式則建構出內含三個元素的陣列,索引 0 開始分別是 10、20、30。
實際上,很少人會直接使用 Array
建構陣列,而會使用陣列實字(Array literal)。例如:
> var array1 = [];
undefined
> array1.length;
0
> var array2 = [];
undefined
> array2.length = 10;
10
> array2.length;
10
> var array3 = [10, 20, 30];
undefined
> array3.length;
3
>
你並沒有看錯,在 JavaScript 中,Array
建立的實例,length
特性是可讀可寫的。例如:
function print(array) {
for(var i = 0; i < array.length; i++) {
console.log(array[i]);
}
}
var array = [1, 2, 3];
print(array); // 1 2 3
console.log('........');
array.length = 5;
print(array); // 1 2 3 undefined undefined
console.log('........');
array.length = 2;
print(array); // 1 2
console.log('........');
array.length = 3;
print(array); // 1 2 undefined
在上面的例子中,陣列原本的長度為 3,後來設定 length
為 5,索引 3 與 4 的部份會是空項目(empty item),指定索引取值的話會是 undefined
,將 length
設為 2 時,原本索引 2 的資料就沒了,就算設回 3 也找不回來了。
索引項目
雖然陣列中的空項目取值的話會是 undefined
,不過,當陣列中有空項目時,運算或函式會有不一致的行為:
> 0 in [1,, 3];
true
> 0 in [,,];
false
> 0 in [undefined, undefined, undefined];
true
> [undefined, undefined].forEach(function(elem) {
... console.log(undefined);
... });
undefined
undefined
undefined
> [,,].forEach(function(elem) {
... console.log(undefined);
... });
undefined
>
從上面的例子來看,陣列中的空項目與 undefined
並不同,可以的話,應避免建立有空項目的陣列。
JavaScript 是以物件來模擬出相似的操作外觀,事實上,用 Array
建構出的物件,索引其實就是以代表數字的特性罷了,事實上索引指定方式也可以用字串,只要它代表數字:
> var array = [1, 2, 3];
undefined
> array['0'];
1
> array['1'];
2
> array['2'];
3
> for(var i in array) {
... console.log(i);
... }
0
1
2
undefined
> delete array[1];
true
> array;
[ 1, <1 empty item>, 3 ]
>
也因此,因為索引其實就是陣列物件上的特性,你也可以用 delete
刪除陣列中的元素,也因此,你可以輕易地使用普通物件,來模擬出陣列的操作外觀:
function print(array) {
for(var i = 0; i < array.length; i++) {
console.log(array[i]);
}
}
// 顯示 100 200 300
print({
'0' : 100,
'1' : 200,
'2' : 300,
length : 3
});
Array 行為
在 JavaScript 中如上模擬出陣列,是非常普遍的應用。那麼,建構 Array
實例,或者說使用陣列實字建構陣列的好處是什麼?當然是為了擁有 Array
已定義的行為,例如自動依元素內容來調整 length
:
> var array = [];
undefined
> array.length;
0
> array[0] = 100;
100
> array.length;
1
> array[10] = 900;
900
> array.length;
11
>
陣列的長度隨時可以增加或減少,指定索引元素時也不一定要連續指定,例如上例中,直接指定了索引 10 為 900,其它未指定的 2 到 9 索引處,全都是 undefined
(就像沒有 2 到 9 的特性名稱罷了),在 JavaScript 中,也沒有所謂陣列超出索引的問題,例如上例若指定 array[10000]
,充其量就是傳回 undefined
。
直接使用 Array
實例來進行陣列操作,還可以獲得 Array
上已定義的方法。例如排序與迭代:
var names = ["Justin", "Monica", "Irene"];
names.sort(function(n1, n2) {
return n1.length - n2.length;
})
.forEach(function(elem) { // Irene Justin Monica
console.log(elem);
});
forEach
是 ECMAScript 5 規範中為 Array
新增的方法,可以指定函式,實際上,只要是類陣列的物件,也可以使用 forEach
。例如:
var obj = {
'0' : 100,
'1' : 200,
'2' : 300,
length : 3
};
obj.forEach = Array.prototype.forEach;
obj.forEach(function(elem, index, arr) {
console.log(elem);
});
obj.forEach(console.log);
上面範例的執行結果是:
100
200
300
100 0 { '0': 100,
'1': 200,
'2': 300,
length: 3,
forEach: [Function: forEach] }
200 1 { '0': 100,
'1': 200,
'2': 300,
length: 3,
forEach: [Function: forEach] }
300 2 { '0': 100,
'1': 200,
'2': 300,
length: 3,
forEach: [Function: forEach] }
陣列中每個元素會作為引數傳入函式,這是 JavaScript 風格的走訪陣列方式,ECMAScript 5 規範的 Array
中,有很多這類接受函式的方法,像是 every
、some
,可以測試陣列元素是否全部符合,以及某個符合條件:
function isLength5(value, index, array) {
return value.length === 5;
}
function lengthLessThan6(value, index, array) {
return value.length < 6;
}
var names = ["Justin", "Monica", "Irene"];
console.log(names.every(isLength5)); // false
console.log(names.some(lengthLessThan6)); // true
處理一串資料時常用的 filter
、map
、reduce
方法當然也有:
var names = ["Justin", "Monica", "Irene"];
var sum = names.filter(function(elem) {
return elem.length > 5;
})
.map(function(elem) {
return elem.length;
})
.reduce(function(accum, elem) {
return accum + elem;
}, 0);
console.log(sum); // 12
reduce
是從陣列索引 0 迭代至尾端,相對地,有個 reduceRight
是從陣列尾端往前迭代至索引 0。除此之外,ECMAScript 5 還新增了 indexOf
、lastIndexOf
方法,更多 Array
上可用的方法,可以參考 Array - JavaScript | MDN。
ES13 以後,陣列有個 at
方法支援負索引。