數(shù)組是值的有序集合。每個(gè)值叫做一個(gè)元素袋毙,而每個(gè)元素在數(shù)組中有一個(gè)位置诬烹,以數(shù)字表示砸烦,稱為索引。
JavaScript數(shù)組的索引是基于0的32位數(shù)值:第一個(gè)元素的索引是0绞吁,最大可能為4294967294(2^32 - 2)幢痘。
通常,數(shù)組的實(shí)現(xiàn)是經(jīng)過(guò)優(yōu)化的掀泳,用數(shù)字索引來(lái)訪問(wèn)數(shù)組元素一般比訪問(wèn)常規(guī)的對(duì)象屬性要快很多雪隧。
實(shí)際上,數(shù)組是對(duì)象的特殊形式员舵,索引可理解為對(duì)象的屬性脑沿,使用[]
訪問(wèn)數(shù)組時(shí),索引首先轉(zhuǎn)換為字符串马僻,然后作為屬性使用庄拇。
JavaScript數(shù)組有以下特點(diǎn):
- 數(shù)組是無(wú)類型的:數(shù)組元素可以是任意類型,并且同一個(gè)數(shù)組中的不同元素也可能有同的類型。
- 數(shù)組是動(dòng)態(tài)的:可以根據(jù)需要增長(zhǎng)或縮減措近。
- 數(shù)組可以是稀疏的:數(shù)組元素的索引不一定是連續(xù)的溶弟,它們之間可以有空缺。
- 數(shù)組繼承自Array.prototype中的屬性瞭郑,它定義了一套豐富的數(shù)組操作方法辜御。
創(chuàng)建數(shù)組
使用直接量創(chuàng)建
var empty = []; // 空數(shù)組
var misc = [1.1, true, "a"]; // 包含3個(gè)不同類型的數(shù)組
var count = [1,,3]; // 包含2個(gè)元素的數(shù)組,中間的值為undefined
使用new創(chuàng)建
var a = new Array(10); // 定義長(zhǎng)度為10的數(shù)組屈张,注:元素為空
var b = new Array(5, 4, 3, "a");// 定義包含4個(gè)元素的數(shù)組擒权,長(zhǎng)度也為4
數(shù)組元素的讀寫(xiě)
所有的數(shù)組都是對(duì)象,可以為其創(chuàng)建任意名字的屬性阁谆。但如果使用的屬性是數(shù)組的索引碳抄,數(shù)組就會(huì)更新length屬性值。
var a = [1]; // 數(shù)組的length為 1
a[-1.23] = true; // 數(shù)組的length為 1场绿,只是數(shù)組多了個(gè)屬性"-1.23"
a["1000"] = 0; // 數(shù)組的length為 1001
a[0.00]; // =>1剖效,相當(dāng)于a[0]
由于數(shù)組也是對(duì)象,所以JavaScript數(shù)組沒(méi)有"越界"的情況焰盗。當(dāng)試圖查詢不存在的屬性時(shí)璧尸,不會(huì)報(bào)錯(cuò),只會(huì)得到undefined值姨谷。
稀疏數(shù)組
稀疏數(shù)組就是包含不連續(xù)索引的數(shù)組逗宁,此時(shí)數(shù)組的length屬性值大于元素的個(gè)數(shù)(undefined不計(jì)入元素個(gè)數(shù))。
var a = [1,,3]; // 第2個(gè)元素為undefined
0 in a; // true
1 in a; // false梦湘,元素不存在
2 in a; // true
a.length; // 3瞎颗,實(shí)際元素為2個(gè)
var b = new Array(3);
0 in b; // false
1 in b; // false
2 in b; // false
b.length; // 3,實(shí)際元素為0個(gè)
var c = [undefined]; // 顯式定義捌议,元素存在
0 in c; // true
c.length; // 1哼拔,實(shí)際元素為1個(gè)
數(shù)組長(zhǎng)度
JavaScript的數(shù)組長(zhǎng)度length是可寫(xiě)的罚渐。
- 當(dāng)length被設(shè)置為小于當(dāng)前值時(shí)煤裙,則多余的元素將被刪除预吆。
- 當(dāng)length被設(shè)置為大于當(dāng)前值時(shí)圣絮,則會(huì)在數(shù)組后創(chuàng)建空的區(qū)域,但并不會(huì)添加元素值只壳。
var a = [1,2,3,4,5];
a.length = 3; // 現(xiàn)在a為[1,2,3]
a.length = 0; // 現(xiàn)在a為[]
a.length = 5; // 長(zhǎng)度為5涧卵,但是沒(méi)有元素捧搞,相當(dāng)于new Array(5)
var b = [1,2,3,4,5];
b.length = 7; // 增大數(shù)組長(zhǎng)度
alert(6 in b); // false, 并沒(méi)有添加元素
alert(b.length); // 7粉怕,但是只有5個(gè)元素
數(shù)組元素的添加和刪除
元素的添加有3種方法:
直接量健民、push()、unshift()贫贝,這3個(gè)方法添加元素后都會(huì)影響數(shù)組的length屬性值秉犹。
元素的刪除有3種方法:
delete蛉谜、pop()、shift()崇堵,這3個(gè)方法中只有delete不會(huì)影響數(shù)組的length屬性值型诚,pop()、shift()都會(huì)影響length屬性值鸳劳。
var a = [1, 2];
a[2] = 3; // a.length = 3
a.push(4); // a.length = 4
a.pop(); // a.length = 3
delete a[1]; // a.length = 3狰贯,注意:delete不改變length屬性,但是a[1]元素變成了undefined
數(shù)組遍歷
for(var i=0; i < a.length; i++) {
// 跳過(guò)元素值為undefined的元素和不存在的元素
if (a[i] == undefined) continue;
}
for(var i=0; i < a.length; i++) {
// 跳過(guò)不存在的元素
if (!(i in a)) continue;
}
由于數(shù)組也是對(duì)象棍辕,所以可以使用for/in對(duì)數(shù)組進(jìn)行遍歷暮现,但是遍歷出的屬性會(huì)包含繼承的屬性,所以一般不使用for/in對(duì)數(shù)組進(jìn)行遍歷楚昭。如果使用,則需要添加過(guò)濾條件:
for(var i in a) {
// 跳過(guò)繼承屬性
if (!a.hasOwnProperty(i)) continue;
}
或者
for(var i in a) {
// 跳過(guò)不是非負(fù)整數(shù)的i
if (String(Math.floor(Math.abs(Number(i)))) !== i) continue;
}
多維數(shù)組
JavaScript不支持真正的多維數(shù)組拍顷,但可以用數(shù)組的數(shù)組來(lái)近似抚太。訪問(wèn)數(shù)組的數(shù)組中的元素,只要簡(jiǎn)單地使用兩次[]
操作符即可昔案。
var table = new Array(10);
for(var i=0; i < table.length; i++)
table[i] = new Array(10);
table[5][7] = 35;
數(shù)組方法
join()
- join()方法將數(shù)組中的所有元素轉(zhuǎn)化為字符串并連接在一起尿贫,返回最后生成的字符串。
- 不修改原始數(shù)組踏揣。
var a = [1, 2, 3];
a.join(); // => "1,2,3"庆亡,默認(rèn)使用","隔開(kāi)元素
a.join("&"); // => "1&2&3",指定分隔符
var b = new Array(10); // 空數(shù)組
b.join("-"); // => "---------"捞稿,9個(gè)分隔符
reverse()
- 將數(shù)組中的元素顛倒順序又谋,返回逆序的原始數(shù)組引用。
- 修改原始數(shù)組娱局。
var a = [1, 2, 3];
a.reverse().join(); // => "3,2,1"彰亥,此時(shí)的a是[3, 2, 1]
sort()
- 將數(shù)組元素進(jìn)行排序,返回排序后的原始數(shù)組引用衰齐。默認(rèn)以字母表順序進(jìn)行排序任斋。
- 修改原始數(shù)組。
var a = new Array("banana", "cherrry", "apple");
a.sort();
var s = a.join(", "); // => "apple, banana, cherrry"耻涛,數(shù)組a現(xiàn)在是["apple", "banana", "cherrry"]
concat()
- 創(chuàng)建并返回一個(gè)新數(shù)組废酷。
- 不修改原始數(shù)組。
var a = [1,2,3];
a.concat(4, 5); // 返回[1,2,3,4,5]
a.concat([4,5]); // 返回[1,2,3,4,5]
a.concat([4,5],[6,7]); // 返回[1,2,3,4,5,6,7]
a.concat(4, [5, [6,7]]);// 返回[1,2,3,4,5,[6,7]]
a.join(); // "1,2,3"抹缕,原始值不發(fā)生改變
slice()
- 對(duì)數(shù)組進(jìn)行切割澈蟆,并返回一個(gè)子數(shù)組。第1個(gè)參數(shù)表示切割的起始索引歉嗓,第2個(gè)參數(shù)表示切割結(jié)束的索引(返回?cái)?shù)組不包含結(jié)束索引對(duì)應(yīng)的元素值)丰介。如果沒(méi)有第2個(gè)參數(shù),則表示取值到最后一個(gè)索引。正值表示正向索引哮幢,負(fù)值表示反向索引带膀。
- 不修改原始數(shù)組。
var a = [1,2,3,4,5];
a.slice(0, 3); // 返回[1,2,3]
a.slice(3); // 返回[4,5]
a.slice(-3, -1); // 返回[3,4]橙垢,反向索引垛叨,從倒數(shù)第3個(gè)到倒數(shù)第1個(gè)元素
splice()
- 從數(shù)組中刪除和插入一些元素。splice()的前2個(gè)參數(shù)指定了要?jiǎng)h除的數(shù)組元素柜某,后面的參數(shù)指定需要插入的元素嗽元。第1個(gè)參數(shù)表示需要?jiǎng)h除元素的起始索引值,第2個(gè)參數(shù)表示需要?jiǎng)h除的個(gè)數(shù)喂击,如果省略則表示刪除起始索引后的所有元素剂癌。
- 修改原始數(shù)組。
var a = [1,2,3,4,5,6,7,8];
a.splice(4); // 返回[5,6,7,8]翰绊,a是[1,2,3,4]
a.splice(1,2); // 返回[2,3]佩谷,a是[1,4]
a.splice(1,1); // 返回[4],a是[1]
var b = [1,2,3,4,5];
a.splice(2,0, "a", "b"); // 返回[]监嗜,a是[1,2, "a","b", 3,4,5]
a.splice(2,2, [1,2], 3); // 返回["a", "b"]谐檀,a是[1,2, [1,2],3, 3,4,5]
push()和pop()
- push()在數(shù)組的尾部添加一個(gè)或多個(gè)元素,并返回?cái)?shù)組新的長(zhǎng)度裁奇。pop()則在數(shù)組的尾部刪除一個(gè)元素桐猬,并返回彈出的元素值。
- 修改原始數(shù)組刽肠。
var stack = [];
stack.push(1,2); // stack:[1,2]溃肪,返回2
stack.push([1,2]); // stack:[1,2, [1,2]],返回3
stack.pop(); // stack:[1,2]五垮,返回[1,2]
unshift()和shift()
- 與push(),pop()不同乍惊,unshift()、shift()在數(shù)組的頭部進(jìn)行添加與刪除操作放仗。unshift()返回新的數(shù)組長(zhǎng)度润绎,shift()返回彈出的數(shù)組元素。
- 修改原始數(shù)組诞挨。
var a = [1];
a.unshift(2); // a:[2, 1]莉撇,返回2
a.unshift(3, [4,5]); // a:[3, [4,5], 2,1],返回4惶傻。 注意:"3,[4,5]"是一次性插入的棍郎,順序不變
a.shift(); // a:[[4,5], 2, 1],返回3
toString()和toLocaleString()
- toString()與不使用任何參數(shù)調(diào)用join()方法返回的字符串是一樣的银室。
- toLocaleString()是toString()的本地化版本涂佃,它調(diào)用元素的toLocaleString()方法將每個(gè)元素轉(zhuǎn)化為字符串励翼,并使用本地化分隔符將元素連接起來(lái)。
[1,2,3].toString(); // "1,2,3"
[1, [2, "c"]].toString(); // "1,2,c"
ECMAScript5中的數(shù)組方法
ECMAScript5中大部分?jǐn)?shù)組方法的第1個(gè)參數(shù)接收一個(gè)函數(shù)辜荠,并且對(duì)數(shù)組的每個(gè)元素調(diào)用一次該函數(shù)汽抚。如果是稀疏數(shù)組,對(duì)不存在的元素不調(diào)用傳遞的函數(shù)伯病。
在大多數(shù)情況下造烁,傳遞的函數(shù)使用3個(gè)參數(shù):數(shù)組元素、元素的索引和數(shù)組本身午笛。通常惭蟋,只需要第1個(gè)參數(shù)值,可以忽略后2個(gè)參數(shù)药磺。
forEach()
- forEach()方法從頭至尾遍歷數(shù)組告组,為每個(gè)元素調(diào)用指定的函數(shù)。
var data = [1,2,3,4,5];
var sum = 0;
data.forEach(function(value) { sum += value;} );
sum; // => 15
- forEach()沒(méi)有像for循環(huán)中使用的相應(yīng)的break語(yǔ)句癌佩。如果要提前終止惹谐,可以做放到try/catch中處理:
function foreach(a, f, t) {
try {
a.forEach(f, t);
}
catch(e) {
if(e === foreach.break) return; // 提前終止
else throw e;
}
}
foreach.break = new Error("StopIteration");
map()
- map()方法為數(shù)組的每個(gè)元素調(diào)用指定的函數(shù),并返回一個(gè)數(shù)組驼卖。
a = [1,2,3];
b = a.map(function(x) {return x*x; }); // b是[1,4,9]
注意:map()返回的是新數(shù)組,它不修改原始數(shù)組鸿秆,如果是稀疏數(shù)組酌畜,返回的也是相同方式的稀疏數(shù)月:它具有相同的長(zhǎng)度,相同的缺失元素卿叽。
filter()
- filter()方法為數(shù)組的每個(gè)元素調(diào)用指定的函數(shù)桥胞,并返回?cái)?shù)組的一個(gè)子集。
- filter()會(huì)跳過(guò)稀疏數(shù)組中缺少的元素考婴,它的返回?cái)?shù)組總是稠密的贩虾。
a = [5,4,3,2,1];
smallvalues = a.filter(function(x) { return x < 3; }); // smallvalues是[2, 1]
every()和some()
- every()方法為數(shù)組的每個(gè)元素調(diào)用指定的函數(shù),并返回true或false沥阱。當(dāng)有一個(gè)調(diào)用返回false時(shí)缎罢,every()就會(huì)返回false;只有當(dāng)所有調(diào)用都是true時(shí)考杉,every()才返回true策精。
- some()方法為數(shù)組的每個(gè)元素調(diào)用指定的函數(shù),并返回true或false崇棠。當(dāng)有一個(gè)調(diào)用返回true時(shí)咽袜,some()就會(huì)返回true;只有當(dāng)所有調(diào)用都是false時(shí)枕稀,some()才返回false询刹。
var a = [1,2,3,4,5];
a.every(function(x) { return x < 10; }); // => true谜嫉,所有的值<10
a.every(function(x) { return x % 2 === 0}); // => false,不是所有的值都是偶數(shù)
a.some(function(x) { return x % 2 === 0; }) // => true凹联,a含有偶數(shù)值
a.some(isNaN); // => false沐兰,a不包含非數(shù)值元素
reduce()和reduceRight()
- reduce()、reduceRight()對(duì)數(shù)組的元素對(duì)調(diào)用指定的函數(shù)匕垫,并返回最終生成的單個(gè)值僧鲁。
- reduce()第1個(gè)參數(shù)指定調(diào)用的函數(shù),第2個(gè)參數(shù)為可選參數(shù)象泵,指定傳遞給函數(shù)的初始值寞秃,當(dāng)不指定值時(shí),使用數(shù)組的第1個(gè)元素作為初始值偶惠。
- reduceRight()的工作原理和reduce()一樣春寿,只是它按照數(shù)組索引從高到低處理數(shù)組。
var a = [1,2,3,4,5];
var sum = a.reduce(function(x,y) { return x+y; }, 0); // 數(shù)組求和
var max = a.reduce(function(x,y) { return (x>y)?x:y; }); // 求最大值
在求和的調(diào)用中忽孽,第1次傳遞的參數(shù)為0(初始值)和1(數(shù)組的第1個(gè)元素)绑改,返回1;第2次調(diào)用使用參數(shù)1(返回值)和2(數(shù)組的第2個(gè)元素)兄一,返回3厘线;然后計(jì)算3+3=6、6+4=10出革、10+5=15造壮。
- 在空數(shù)組上,不帶初始值調(diào)用reduce將導(dǎo)致類型錯(cuò)誤異常骂束。
- 如果數(shù)組只有一個(gè)元素并且沒(méi)有指定初始值耳璧,或者有一個(gè)空數(shù)組并且指定一個(gè)初始值,reduce()只是簡(jiǎn)單地返回那個(gè)值而不會(huì)調(diào)用函數(shù)展箱。
indexOf()和lastIndexOf()
- indexOf()和lastIndexOf()搜索整個(gè)數(shù)組中給定值的元素旨枯,返回找到的第1個(gè)元素的索引,如果找不到混驰,則返回-1攀隔。
- 第1個(gè)參數(shù)為需要搜索的值,第2個(gè)參數(shù)是可選的账胧,指定開(kāi)始搜索的索引位置竞慢。
var a = [0,1,2,1,0];
a.indexOf(1); // =>1: a[1] = 1
a.lastIndexOf(1); // =>3: a[3] = 1
a.indexOf(3); // =>-1: a中沒(méi)有值為3的元素
數(shù)組類型判斷
在ECMAScript5中,可以使用Array.isArray()來(lái)判斷一個(gè)對(duì)象是否是數(shù)組治泥。
Array.isArray([]); // true
Array.isArray({}); // false
在ECMAScript3中isArray()函數(shù)的代碼可以這樣寫(xiě):
var isArray = Function.isArray || function(o) {
return typeof o === "object" &&
Object.prototype.toString.call(o) === "[objet Array]";
};
類數(shù)組對(duì)象
數(shù)組有一些特性是其他對(duì)象所有沒(méi)有的:
- 當(dāng)添加元素時(shí)筹煮,自動(dòng)更新length屬性
- 設(shè)置length為較小值時(shí),將截?cái)鄶?shù)組居夹。
- 從Array.prototype中繼承了一些有用的方法败潦。
- 類屬性為"Array"
這些特性讓數(shù)組與常規(guī)的對(duì)象有明顯的區(qū)別本冲。但是它們不是定義數(shù)組的本質(zhì)特性。
可以把擁有數(shù)值length屬性和對(duì)應(yīng)非負(fù)整數(shù)屬性的對(duì)象看作是一種類型的數(shù)組劫扒。
很多數(shù)組算法針對(duì)類數(shù)組對(duì)象工作得很好檬洞,就像針對(duì)真正的數(shù)組一樣。
定義一個(gè)類數(shù)組對(duì)象沟饥,如下所示:
var a = {};
var i = 0;
while(i < 10) {
a[i] = i*i;
i++;
}
a.length = i;
// 現(xiàn)在添怔,可以當(dāng)真正的數(shù)組進(jìn)行遍歷操作
var total = 0;
for(var j=0; j < a.length; j++)
total += a[j];
Arguments對(duì)象就是一個(gè)類數(shù)組對(duì)象;在客戶端JavaScript中贤旷,一些DOM方法(如document.getElementsByTagName())也返回類數(shù)組對(duì)象广料。
作為數(shù)組的字符串
- 在ECMAScript5中,字符串的行為類似于只讀的數(shù)組幼驶。除了使用charAt()方法訪問(wèn)單個(gè)字符外艾杏,還可以使用方括號(hào)訪問(wèn)。
- 字符串的類似數(shù)組的特性使得通用的數(shù)組方法也可以應(yīng)用到字符串上盅藻。
s = "JavaScript";
Array.prototype.join.call(s, " "); // => "J a v a S c r i p t"
注意:不能使用會(huì)修改數(shù)組原始值的算法(如,reverse(), sort())操作字符串购桑,否則會(huì)拋出類型錯(cuò)誤異常。