前面的話
數(shù)組是一組按序排列的值,相對(duì)地,對(duì)象的屬性名稱(chēng)是無(wú)序的。從本質(zhì)上講,數(shù)組使用數(shù)字作為查找鍵,而對(duì)象擁有用戶(hù)自定義的屬性名。javascript沒(méi)有真正的關(guān)聯(lián)數(shù)組,但對(duì)象可用于實(shí)現(xiàn)關(guān)聯(lián)的功能
Array()僅僅是一種特殊類(lèi)型的Object(),也就是說(shuō),Array()實(shí)例基本上是擁有一些額外功能的Object()實(shí)例。數(shù)組可以保存任何類(lèi)型的值,這些值可以隨時(shí)更新或刪除,且數(shù)組的大小是動(dòng)態(tài)調(diào)整的
除了對(duì)象之外,數(shù)組Array類(lèi)型可能是javascript中最常用的類(lèi)型了。而且,javascript中的數(shù)組與其他多數(shù)語(yǔ)言中的數(shù)組有著相當(dāng)大的區(qū)別。本文將介紹javascript中的數(shù)組Array類(lèi)型
創(chuàng)建數(shù)組
有兩種創(chuàng)建數(shù)組的方法:使用字面量語(yǔ)法和使用Array()構(gòu)造函數(shù)
【字面量】
使用數(shù)組字面量是創(chuàng)建數(shù)組最簡(jiǎn)單的方法,在方括號(hào)中將數(shù)組元素用逗號(hào)隔開(kāi)即可
var empty = []; //沒(méi)有元素的數(shù)組
var primes = [2,3,5,7,11]; //有5個(gè)數(shù)值的數(shù)組
雖然javascript數(shù)組與其他語(yǔ)言中的數(shù)組都是數(shù)據(jù)的有序列表,但與其他語(yǔ)言不同的是,javascript數(shù)組的每一項(xiàng)可以保存任何類(lèi)型的數(shù)據(jù)
var misc = [1.1,true, "a"]; //3個(gè)不同類(lèi)型的元素
數(shù)組字面量中的值不一定要是常量,它們可以是任意的表達(dá)式
var base = 1024;
var table = [base,base+1,base+2,base+3];
它可以包含對(duì)象字面量或其他數(shù)組字面量
var b = [ [1,{x:1,y:2}],[2,{x:3,y:4}] ];
如果數(shù)組的元素還是數(shù)組,就形成了多維數(shù)組
var a = [[1, 2], [3, 4]];
[注意]使用數(shù)字字面量表示法時(shí),不會(huì)調(diào)用Array構(gòu)造函數(shù)
【構(gòu)造函數(shù)】
有三種方式調(diào)用構(gòu)造函數(shù)
【1】沒(méi)有參數(shù),創(chuàng)建一個(gè)空數(shù)組
//該方法創(chuàng)建一個(gè)沒(méi)有任何元素的空數(shù)組,等同于數(shù)組直接量[]
var a = new Array();
【2】有一個(gè)數(shù)值參數(shù),該參數(shù)用于指定數(shù)組的長(zhǎng)度
var a = new Array(10);
console.log(a);//[]
console.log(a[0],a.length);//undefined 10
[注意]若存在一個(gè)其他類(lèi)型的參數(shù),則會(huì)創(chuàng)建包含那個(gè)值的只有一項(xiàng)的數(shù)組
var a = new Array('10');
console.log(a);//['10']
console.log(a[0],a.length);//10 1
【3】有多個(gè)參數(shù)時(shí),參數(shù)表示為數(shù)組的具體元素
var a = new Array(1,2,3);
console.log(a);//[1,2,3]
console.log(a[0],a[1],a[2]);//1 2 3
使用Array()構(gòu)造函數(shù)時(shí),可以省略new操作符
var a1 = Array();
var a2 = Array(10);
var a3 = Array(1,2,3);
console.log(a1,a2,a3);//[] [] [1,2,3]
數(shù)組本質(zhì)
數(shù)組是按次序排列的一組值,本質(zhì)上,數(shù)組是一種特殊的對(duì)象
typeof [1, 2, 3] // "object"
數(shù)組的特殊性體現(xiàn)在,它的鍵名是按次序排列的一組整數(shù)(0,1,2…)。由于數(shù)組成員的鍵名是固定的,因此數(shù)組不用為每個(gè)元素指定鍵名,而對(duì)象的每個(gè)成員都必須指定鍵名
var arr = ['a', 'b', 'c'];
console.log(Object.keys(arr));// ["0", "1", "2"]
var obj = {
name1: 'a',
name2: 'b',
name3: 'c'
};
數(shù)組是對(duì)象的特殊形式,使用方括號(hào)訪問(wèn)數(shù)組元素就像用方括號(hào)訪問(wèn)對(duì)象的屬性一樣
javascript語(yǔ)言規(guī)定,對(duì)象的鍵名一律為字符串,所以,數(shù)組的鍵名其實(shí)也是字符串。之所以可以用數(shù)值讀取,是因?yàn)榉亲址逆I名會(huì)被轉(zhuǎn)為字符串,然后將其作為屬性名來(lái)使用
o={}; //創(chuàng)建一個(gè)普通的對(duì)象
o[1]="one"; //用一個(gè)整數(shù)來(lái)索引它
//數(shù)值鍵名被自動(dòng)轉(zhuǎn)成字符串
var arr = ['a', 'b', 'c'];
arr['0'] // 'a'
arr[0] // 'a'
但是,一定要區(qū)分?jǐn)?shù)組索引和對(duì)象的屬性名:所有的索引都是屬性名,但只有在0~232-2(4294967294)之間的整數(shù)屬性名才是索引
var a = [];
//索引
a['1000'] = 'abc';
a[1000] // 'abc'
//索引
a[1.00] = 6;
a[1] // 6
[注意]單獨(dú)的數(shù)值不能作為標(biāo)識(shí)符(identifier)。所以,數(shù)組成員只能用方括號(hào)法表示
var arr = [1, 2, 3];
arr[0];//1
arr.0;//SyntaxError
可以使用負(fù)數(shù)或非整數(shù)來(lái)索引數(shù)組。但由于其不在0~2的32次方-2的范圍內(nèi),所以其只是數(shù)組的屬性名,而不是數(shù)組的索引,明顯的特征是不改變數(shù)組的長(zhǎng)度
var a = [1,2,3];
//屬性名
a[-1.23]=true;
console.log(a.length);//3
//索引
a[10] = 5;
console.log(a.length);//11
//屬性名
a['abc']='testing';
console.log(a.length);//11
稀疏數(shù)組
稀疏數(shù)組就是包含從0開(kāi)始的不連續(xù)索引的數(shù)組
【1】制造稀疏數(shù)組最直接的方法就是使用delete操作符
var a = [1,2,3,4,5];
delete a[1];
console.log(a[1]);//undefined
console.log(1 in a);//false
【2】數(shù)組的逗號(hào)之間可以省略元素值,通過(guò)省略元素值也可以制造稀疏數(shù)組
var a =[1,,3,4,5];
console.log(a[1]);//undefined
console.log(1 in a);//false
[注意]省略的元素值和值為undefined的元素值是有區(qū)別的
var a =[1,,3,4,5];
console.log(a[1]);//undefined
console.log(1 in a);//false
var a =[1,undefined,3,4,5];
console.log(a[1]);//undefined
console.log(1 in a);//true
如果在數(shù)組的末尾使用逗號(hào)時(shí),瀏覽器之間是有差別的。標(biāo)準(zhǔn)瀏覽器會(huì)忽略該逗號(hào),而IE8-瀏覽器則會(huì)在末尾添加undefined值
//標(biāo)準(zhǔn)瀏覽器輸出[1,2],而IE8-瀏覽器輸出[1,2,undefined]
var a = [1,2,];
console.log(a);
//標(biāo)準(zhǔn)瀏覽器輸出2,而IE8-瀏覽器輸出3
var a = [,,];
console.log(a.length);
足夠稀疏的數(shù)組通常在實(shí)現(xiàn)上比稠密的數(shù)組更慢,內(nèi)存利用率更高,在這樣的數(shù)組中查找元素的時(shí)間與常規(guī)對(duì)象屬性的查找時(shí)間一樣長(zhǎng)
數(shù)組長(zhǎng)度
每個(gè)數(shù)組有一個(gè)length屬性,就是這個(gè)屬性使其區(qū)別于常規(guī)的JavaScript對(duì)象。針對(duì)稠密(也就是非稀疏)數(shù)組,length屬性值代表數(shù)組中元素的個(gè)數(shù),其值比數(shù)組中最大的索引大1
[].length //=>0:數(shù)組沒(méi)有元素
['a','b','c'].length //=>3:最大的索引為2,length為3
當(dāng)數(shù)組是稀疏數(shù)組時(shí),length屬性值大于元素的個(gè)數(shù),同樣地,其值比數(shù)組中最大的索引大1
[,,,].length; //3
(Array(10)).length;//10
var a = [1,2,3];
console.log(a.length);//3
delete a[1];
console.log(a.length);//3
數(shù)組的特殊性主要體現(xiàn)在數(shù)組長(zhǎng)度是可以動(dòng)態(tài)調(diào)整的:
【1】如果為一個(gè)數(shù)組元素賦值,索引i大于等于現(xiàn)有數(shù)組的長(zhǎng)度時(shí),length屬性的值將設(shè)置為i+1
var arr = ['a', 'b'];
arr.length // 2
arr[2] = 'c';
arr.length // 3
arr[9] = 'd';
arr.length // 10
arr[1000] = 'e';
arr.length // 1001
【2】設(shè)置length屬性為小于當(dāng)前長(zhǎng)度的非負(fù)整數(shù)n時(shí),當(dāng)前數(shù)組索引值大于等于n的元素將從中刪除
a=[1,2,3,4,5]; //從5個(gè)元素的數(shù)組開(kāi)始
a.length = 3; //現(xiàn)在a為[1,2,3]
a.length = 0; //刪除所有的元素。a為[]
a.length = 5; //長(zhǎng)度為5,但是沒(méi)有元素,就像new
Array(5)
[注意]將數(shù)組清空的一個(gè)有效方法,就是將length屬性設(shè)為0
var arr = [ 'a', 'b', 'c' ];
arr.length = 0;
arr // []
【3】將數(shù)組的length屬性值設(shè)置為大于其當(dāng)前的長(zhǎng)度。實(shí)際上這不會(huì)向數(shù)組中添加新的元素,它只是在數(shù)組尾部創(chuàng)建一個(gè)空的區(qū)域
var a = ['a'];
a.length = 3;
console.log(a[1]);//undefined
console.log(1 in a);//false
如果人為設(shè)置length為不合法的值(即0——232-2范圍以外的值),javascript會(huì)報(bào)錯(cuò)
// 設(shè)置負(fù)值
[].length = -1// RangeError: Invalid array length
// 數(shù)組元素個(gè)數(shù)大于等于2的32次方
[].length = Math.pow(2,32)// RangeError: Invalid array length
// 設(shè)置字符串
[].length = 'abc'// RangeError: Invalid array length
由于數(shù)組本質(zhì)上是對(duì)象,所以可以為數(shù)組添加屬性,但是這不影響length屬性的值
var a = [];
a['p'] = 'abc';
console.log(a.length);// 0
a[2.1] = 'abc';
console.log(a.length);// 0
數(shù)組遍歷
使用for循環(huán)遍歷數(shù)組元素最常見(jiàn)的方法
var a = [1, 2, 3];
for(var i = 0; i < a.length; i++) {
console.log(a[i]);
}
當(dāng)然,也可以使用while循環(huán)
var a = [1, 2, 3];
var i = 0;
while (i < a.length) {
console.log(a[i]);
i++;
}
var l = a.length;
while (l--) {
console.log(a[l]);
}
但如果數(shù)組是稀疏數(shù)組時(shí),使用for循環(huán),就需要添加一些條件
//跳過(guò)不存在的元素
var a = [1,,,2];
for(var i = 0; i < a.length; i++){
if(!(i in a)) continue;
console.log(a[i]);
}
還可以使用for/in循環(huán)處理稀疏數(shù)組。循環(huán)每次將一個(gè)可枚舉的屬性名(包括數(shù)組索引)賦值給循環(huán)變量。不存在的索引將不會(huì)遍歷到
var a = [1,,,2];
for(var i in a){
console.log(a[i]);
}
由于for/in循環(huán)能夠枚舉繼承的屬性名,如添加到Array.prototype中的方法。由于這個(gè)原因,在數(shù)組上不應(yīng)該使用for/in循環(huán),除非使用額外的檢測(cè)方法來(lái)過(guò)濾不想要的屬性
var a = [1,,,2];
a.b = 'b';
for(var i in a){
console.log(a[i]);//1 2 'b'
}
//跳過(guò)不是非負(fù)整數(shù)的i
var a = [1,,,2];
a.b = 'b';
for(var i in a){
if(String(Math.floor(Math.abs(Number(i)))) !== i) continue;
console.log(a[i]);//1 2
}
javascript規(guī)范允許for/in循環(huán)以不同的順序遍歷對(duì)象的屬性。通常數(shù)組元素的遍歷實(shí)現(xiàn)是升序的,但不能保證一定是這樣的。特別地,如果數(shù)組同時(shí)擁有對(duì)象屬性和數(shù)組元素,返回的屬性名很可能是按照創(chuàng)建的順序而非數(shù)值的大小順序。如果算法依賴(lài)于遍歷的順序,那么最好不要使用for/in而用常規(guī)的for循環(huán)
類(lèi)數(shù)組
擁有l(wèi)ength屬性和對(duì)應(yīng)非負(fù)整數(shù)屬性的對(duì)象叫做類(lèi)數(shù)組(array-like object)
//類(lèi)數(shù)組演示
var a = {};
var i = 0;
while(i < 10){
a[i] = i*i;
i++;
}
a.length = i;
var total = 0;
for(var j = 0; j < a.length; j++){
total += a[j];
}
有三個(gè)常見(jiàn)的類(lèi)數(shù)組對(duì)象:
【1】arguments對(duì)象
// arguments對(duì)象
function args() { return arguments }
var arrayLike = args('a', 'b');
arrayLike[0] // 'a'
arrayLike.length // 2
arrayLike instanceof Array // false
【2】DOM方法(如document.getElementsByTagName()方法)返回的對(duì)象
// DOM元素
var elts = document.getElementsByTagName('h3');
elts.length // 3
elts instanceof Array // false
【3】字符串
// 字符串
'abc'[1] // 'b'
'abc'.length // 3
'abc' instanceof Array // false
[注意]字符串是不可變值,故當(dāng)把它們作為數(shù)組看待時(shí),它們是只讀的。如push()、sort()、reverse()、splice()等數(shù)組方法會(huì)修改數(shù)組,它們?cè)谧址鲜菬o(wú)效的,且會(huì)報(bào)錯(cuò)
var str = 'abc';
Array.prototype.forEach.call(str, function(chr) {
console.log(chr);//a b c
});
Array.prototype.splice.call(str,1);
console.log(str);//TypeError: Cannot delete property '2' of [object String]
數(shù)組的slice方法將類(lèi)數(shù)組對(duì)象變成真正的數(shù)組
var arr = Array.prototype.slice.call(arrayLike);
javascript數(shù)組方法是特意定義為通用的,因此它們不僅應(yīng)用在真正的數(shù)組而且在類(lèi)數(shù)組對(duì)象上都能正確工作。在ECMAScript5中,所有的數(shù)組方法都是通用的。在ECMAScript3中,除了toString()和toLocaleString()以外的所有方法也是通用的
var a = {'0':'a','1':'b','2':'c',length:3};
Array.prototype.join.call(a,'+');//'a+b+c'
Array.prototype.slice.call(a,0);//['a','b','c']
Array.prototype.map.call(a,function(x){return x.toUpperCase();});//['A','B','C']