前面的話
數組是一組按序排列的值,相對地,對象的屬性名稱是無序的。從本質上講,數組使用數字作為尋找鍵,而對象擁有使用者自訂的屬性名稱。javascript沒有真正的關聯陣列,但對象可用於實現關聯的功能
Array()僅僅是一種特殊類型的Object(),也就是說,Array()執行個體基本上是擁有一些額外功能的Object()執行個體。數組可以儲存任何類型的值,這些值可以隨時更新或刪除,且數組的大小是動態調整的
除了對象之外,數組Array類型可能是javascript中最常用的類型了。而且,javascript中的數組與其他多數語言中的數組有著相當大的區別。本文將介紹javascript中的數組Array類型
建立數組
有兩種建立數組的方法:使用字面量文法和使用Array()建構函式
【字面量】
使用數組字面量是建立數組最簡單的方法,在方括弧中將數組元素用逗號隔開即可
var empty = []; //沒有元素的數組var primes = [2,3,5,7,11]; //有5個數值的數組
雖然javascript數組與其他語言中的數組都是資料的有序列表,但與其他語言不同的是,javascript數組的每一項可以儲存任何類型的資料
var misc = [1.1,true, "a"]; //3個不同類型的元素
數組字面量中的值不一定要是常量,它們可以是任意的運算式
var base = 1024;var table = [base,base+1,base+2,base+3];
它可以包含對象字面量或其他數組字面量
var b = [ [1,{x:1,y:2}],[2,{x:3,y:4}] ];
如果數組的元素還是數組,就形成了多維陣列
var a = [[1, 2], [3, 4]];
[注意]使用數字字面量標記法時,不會調用Array建構函式
【建構函式】
有三種方式調用建構函式
【1】沒有參數,建立一個空數組
//該方法建立一個沒有任何元素的空數組,等同於數組直接量[]var a = new Array();
【2】有一個數值參數,該參數用於指定數組的長度
var a = new Array(10);console.log(a);//[]console.log(a[0],a.length);//undefined 10
[注意]若存在一個其他類型的參數,則會建立包含那個值的只有一項的數組
var a = new Array('10');console.log(a);//['10']console.log(a[0],a.length);//10 1
【3】有多個參數時,參數表示為數組的具體元素
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()建構函式時,可以省略new操作符
var a1 = Array();var a2 = Array(10);var a3 = Array(1,2,3);console.log(a1,a2,a3);//[] [] [1,2,3]
數組本質
數組是按次序排列的一組值,本質上,數組是一種特殊的對象
typeof [1, 2, 3] // "object"
數組的特殊性體現在,它的鍵名是按次序排列的一組整數(0,1,2…)。由於數群組成員的鍵名是固定的,因此數組不用為每個元素指定鍵名,而對象的每個成員都必須指定鍵名
var arr = ['a', 'b', 'c'];console.log(Object.keys(arr));// ["0", "1", "2"]var obj = {name1: 'a',name2: 'b',name3: 'c'};
數組是對象的特殊形式,使用方括弧訪問數組元素就像用方括弧訪問對象的屬性一樣
javascript語言規定,對象的鍵名一律為字串,所以,數組的鍵名其實也是字串。之所以可以用數值讀取,是因為非字串的鍵名會被轉為字串,然後將其作為屬性名稱來使用
o={}; //建立一個普通的對象o[1]="one"; //用一個整數來索引它//數值鍵名被自動轉成字串var arr = ['a', 'b', 'c'];arr['0'] // 'a'arr[0] // 'a'
但是,一定要區分數組索引和對象的屬性名稱:所有的索引都是屬性名稱,但只有在0~232-2(4294967294)之間的整數屬性名稱才是索引
var a = [];//索引a['1000'] = 'abc';a[1000] // 'abc'//索引a[1.00] = 6;a[1] // 6
[注意]單獨的數值不能作為標識符(identifier)。所以,數群組成員只能用方括弧法表示
var arr = [1, 2, 3];arr[0];//1arr.0;//SyntaxError
可以使用負數或非整數來索引數組。但由於其不在0~2的32次方-2的範圍內,所以其只是數組的屬性名稱,而不是數組的索引,明顯的特徵是不改變數組的長度
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
稀疏數組
稀疏數組就是包含從0開始的不連續索引的數組
【1】製造稀疏數組最直接的方法就是使用delete操作符
var a = [1,2,3,4,5];delete a[1];console.log(a[1]);//undefinedconsole.log(1 in a);//false
【2】數組的逗號之間可以省略元素值,通過省略元素值也可以製造稀疏數組
var a =[1,,3,4,5];console.log(a[1]);//undefinedconsole.log(1 in a);//false
[注意]省略的元素值和值為undefined的元素值是有區別的
var a =[1,,3,4,5];console.log(a[1]);//undefinedconsole.log(1 in a);//falsevar a =[1,undefined,3,4,5];console.log(a[1]);//undefinedconsole.log(1 in a);//true
如果在數組的末尾使用逗號時,瀏覽器之間是有差別的。標準瀏覽器會忽略該逗號,而IE8-瀏覽器則會在末尾添加undefined值
//標準瀏覽器輸出[1,2],而IE8-瀏覽器輸出[1,2,undefined]var a = [1,2,];console.log(a);//標準瀏覽器輸出2,而IE8-瀏覽器輸出3var a = [,,];console.log(a.length);
足夠稀疏的數組通常在實現上比稠密的數組更慢,記憶體利用率更高,在這樣的數組中尋找元素的時間與常規對象屬性的尋找時間一樣長
數組長度
每個數組有一個length屬性,就是這個屬性使其區別於常規的JavaScript對象。針對稠密(也就是非稀疏)數組,length屬性值代表數組中元素的個數,其值比數組中最大的索引大1
[].length //=>0:數組沒有元素['a','b','c'].length //=>3:最大的索引為2,length為3
當數組是稀疏數組時,length屬性值大於元素的個數,同樣地,其值比數組中最大的索引大1
[,,,].length; //3(Array(10)).length;//10var a = [1,2,3];console.log(a.length);//3delete a[1];console.log(a.length);//3
數組的特殊性主要體現在數組長度是可以動態調整的:
【1】如果為一個數組元素賦值,索引i大於等於現有數組的長度時,length屬性的值將設定為i+1
var arr = ['a', 'b'];arr.length // 2arr[2] = 'c';arr.length // 3arr[9] = 'd';arr.length // 10arr[1000] = 'e';arr.length // 1001
【2】設定length屬性為小於當前長度的非負整數n時,當前數組索引值大於等於n的元素將從中刪除
a=[1,2,3,4,5]; //從5個元素的數組開始a.length = 3; //現在a為[1,2,3]a.length = 0; //刪除所有的元素。a為[]a.length = 5; //長度為5,但是沒有元素,就像new
Array(5)
[注意]將數組清空的一個有效方法,就是將length屬性設為0
var arr = [ 'a', 'b', 'c' ];arr.length = 0;arr // []
【3】將數組的length屬性值設定為大於其當前的長度。實際上這不會向數組中添加新的元素,它只是在數組尾部建立一個空的地區
var a = ['a'];a.length = 3;console.log(a[1]);//undefinedconsole.log(1 in a);//false
如果人為設定length為不合法的值(即0——232-2範圍以外的值),javascript會報錯
// 設定負值[].length = -1// RangeError: Invalid array length// 數組元素個數大於等於2的32次方[].length = Math.pow(2,32)// RangeError: Invalid array length// 設定字串[].length = 'abc'// RangeError: Invalid array length
由於數組本質上是對象,所以可以為數組添加屬性,但是這不影響length屬性的值
var a = [];a['p'] = 'abc';console.log(a.length);// 0a[2.1] = 'abc';console.log(a.length);// 0
數組遍曆
使用for迴圈遍曆數組元素最常見的方法
var a = [1, 2, 3];for(var i = 0; i < a.length; i++) {console.log(a[i]);}
當然,也可以使用while迴圈
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]);}
但如果數組是稀疏數組時,使用for迴圈,就需要添加一些條件
//跳過不存在的元素var a = [1,,,2];for(var i = 0; i < a.length; i++){if(!(i in a)) continue;console.log(a[i]);}
還可以使用for/in迴圈處理稀疏數組。迴圈每次將一個可枚舉的屬性名稱(包括數組索引)賦值給迴圈變數。不存在的索引將不會遍曆到
var a = [1,,,2];for(var i in a){console.log(a[i]);}
由於for/in迴圈能夠枚舉繼承的屬性名稱,如添加到Array.prototype中的方法。由於這個原因,在數組上不應該使用for/in迴圈,除非使用額外的檢測方法來過濾不想要的屬性
var a = [1,,,2];a.b = 'b';for(var i in a){console.log(a[i]);//1 2 'b'} //跳過不是非負整數的ivar 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規範允許for/in迴圈以不同的順序遍曆對象的屬性。通常數組元素的遍曆實現是升序的,但不能保證一定是這樣的。特別地,如果數組同時擁有對象屬性和數組元素,返回的屬性名稱很可能是按照建立的順序而非數值的大小順序。如果演算法依賴於遍曆的順序,那麼最好不要使用for/in而用常規的for迴圈
類數組
擁有length屬性和對應非負整數屬性的對象叫做類數組(array-like object)
//類數組示範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];}
有三個常見的類數組對象:
【1】arguments對象
// arguments對象function args() { return arguments }var arrayLike = args('a', 'b');arrayLike[0] // 'a'arrayLike.length // 2arrayLike instanceof Array // false
【2】DOM方法(如document.getElementsByTagName()方法)返回的對象
// DOM元素var elts = document.getElementsByTagName('h3');elts.length // 3elts instanceof Array // false
【3】字串
// 字串'abc'[1] // 'b''abc'.length // 3'abc' instanceof Array // false
[注意]字串是不可變值,故當把它們作為數組看待時,它們是唯讀。如push()、sort()、reverse()、splice()等數組方法會修改數組,它們在字串上是無效的,且會報錯
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]
數組的slice方法將類數組對象變成真正的數組
var arr = Array.prototype.slice.call(arrayLike);
javascript數組方法是特意定義為通用的,因此它們不僅應用在真正的數組而且在類數組對象上都能正確工作。在ECMAScript5中,所有的數組方法都是通用的。在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']