數(shù)組

定義

數(shù)組(array)是按次序排列的一組值。每個值的位置都有編號(從0開始)侍匙,整個數(shù)組用方括號表示。

var arr = ['a', 'b', 'c'];

上面代碼中的a叮雳、b想暗、c就構(gòu)成一個數(shù)組,兩端的方括號是數(shù)組的標(biāo)志债鸡。a是0號位置江滨,b是1號位置,c是2號位置厌均。

除了在定義時賦值唬滑,數(shù)組也可以先定義后賦值。

var arr = [];

arr[0] = 'a';
arr[1] = 'b';
arr[2] = 'c';

任何類型的數(shù)據(jù)棺弊,都可以放入數(shù)組晶密。

var arr = [
  {a: 1},
  [1, 2, 3],
  function() {return true;}
];

arr[0] // Object {a: 1}
arr[1] // [1, 2, 3]
arr[2] // function (){return true;}

上面數(shù)組arr的3個成員依次是對象、數(shù)組模她、函數(shù)稻艰。

如果數(shù)組的元素還是數(shù)組,就形成了多維數(shù)組侈净。

var a = [[1, 2], [3, 4]];
a[0][1] // 2
a[1][1] // 4

數(shù)組的本質(zhì)

本質(zhì)上尊勿,數(shù)組屬于一種特殊的對象。typeof運算符會返回數(shù)組的類型是object畜侦。

typeof [1, 2, 3] // "object"

上面代碼表明元扔,typeof運算符認(rèn)為數(shù)組的類型就是對象。

數(shù)組的特殊性體現(xiàn)在旋膳,它的鍵名是按次序排列的一組整數(shù)(0澎语,1,2…)。

var arr = ['a', 'b', 'c'];

Object.keys(arr)
// ["0", "1", "2"]

上面代碼中擅羞,Object.keys方法返回數(shù)組的所有鍵名尸变。可以看到數(shù)組的鍵名就是整數(shù)0减俏、1召烂、2。

由于數(shù)組成員的鍵名是固定的(默認(rèn)總是0垄懂、1骑晶、2…),因此數(shù)組不用為每個元素指定鍵名草慧,而對象的每個成員都必須指定鍵名桶蛔。JavaScript 語言規(guī)定,對象的鍵名一律為字符串漫谷,所以仔雷,數(shù)組的鍵名其實也是字符串。之所以可以用數(shù)值讀取舔示,是因為非字符串的鍵名會被轉(zhuǎn)為字符串碟婆。

var arr = ['a', 'b', 'c'];

arr['0'] // 'a'
arr[0] // 'a'

上面代碼分別用數(shù)值和字符串作為鍵名,結(jié)果都能讀取數(shù)組惕稻。原因是數(shù)值鍵名被自動轉(zhuǎn)為了字符串竖共。

注意,這點在賦值時也成立俺祠。如果一個值總是先轉(zhuǎn)成字符串公给,再進(jìn)行賦值。

var a = [];

a[1.00] = 6;
a[1] // 6

上面代碼中蜘渣,由于1.00轉(zhuǎn)成字符串是1淌铐,所以通過數(shù)字鍵1可以讀取值。

上一章說過蔫缸,對象有兩種讀取成員的方法:點結(jié)構(gòu)(object.key)和方括號結(jié)構(gòu)(object[key])腿准。但是,對于數(shù)值的鍵名拾碌,不能使用點結(jié)構(gòu)吐葱。

var arr = [1, 2, 3];
arr.0 // SyntaxError

上面代碼中,arr.0的寫法不合法校翔,因為單獨的數(shù)值不能作為標(biāo)識符(identifier)唇撬。所以,數(shù)組成員只能用方括號arr[0]表示(方括號是運算符展融,可以接受數(shù)值)。

length 屬性

數(shù)組的length屬性,返回數(shù)組的成員數(shù)量告希。

['a', 'b', 'c'].length // 3

JavaScript 使用一個32位整數(shù)扑浸,保存數(shù)組的元素個數(shù)。這意味著燕偶,數(shù)組成員最多只有 4294967295 個(232 - 1)個喝噪,也就是說length屬性的最大值就是 4294967295。

只要是數(shù)組指么,就一定有length屬性酝惧。該屬性是一個動態(tài)的值,等于鍵名中的最大整數(shù)加上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

上面代碼表示晚唇,數(shù)組的數(shù)字鍵不需要連續(xù),length屬性的值總是比最大的那個整數(shù)鍵大1盗似。另外哩陕,這也表明數(shù)組是一種動態(tài)的數(shù)據(jù)結(jié)構(gòu),可以隨時增減數(shù)組的成員赫舒。

length屬性是可寫的悍及。如果人為設(shè)置一個小于當(dāng)前成員個數(shù)的值,該數(shù)組的成員會自動減少到length設(shè)置的值接癌。

var arr = [ 'a', 'b', 'c' ];
arr.length // 3

arr.length = 2;
arr // ["a", "b"]

上面代碼表示心赶,當(dāng)數(shù)組的length屬性設(shè)為2(即最大的整數(shù)鍵只能是1)那么整數(shù)鍵2(值為c)就已經(jīng)不在數(shù)組中了,被自動刪除了缺猛。

清空數(shù)組的一個有效方法缨叫,就是將length屬性設(shè)為0。

var arr = [ 'a', 'b', 'c' ];

arr.length = 0;
arr // []

如果人為設(shè)置length大于當(dāng)前元素個數(shù)枯夜,則數(shù)組的成員數(shù)量會增加到這個值弯汰,新增的位置都是空位。

var a = ['a'];

a.length = 3;
a[1] // undefined

上面代碼表示湖雹,當(dāng)length屬性設(shè)為大于數(shù)組個數(shù)時咏闪,讀取新增的位置都會返回undefined

如果人為設(shè)置length為不合法的值摔吏,JavaScript 會報錯鸽嫂。

// 設(shè)置負(fù)值
[].length = -1
// RangeError: Invalid array length

// 數(shù)組元素個數(shù)大于等于2的32次方
[].length = Math.pow(2, 32)
// RangeError: Invalid array length

// 設(shè)置字符串
[].length = 'abc'
// RangeError: Invalid array length

值得注意的是,由于數(shù)組本質(zhì)上是一種對象征讲,所以可以為數(shù)組添加屬性据某,但是這不影響length屬性的值。

var a = [];

a['p'] = 'abc';
a.length // 0

a[2.1] = 'abc';
a.length // 0

上面代碼將數(shù)組的鍵分別設(shè)為字符串和小數(shù)诗箍,結(jié)果都不影響length屬性癣籽。因為,length屬性的值就是等于最大的數(shù)字鍵加1,而這個數(shù)組沒有整數(shù)鍵筷狼,所以length屬性保持為0瓶籽。

如果數(shù)組的鍵名是添加超出范圍的數(shù)值,該鍵名會自動轉(zhuǎn)為字符串埂材。

var arr = [];
arr[-1] = 'a';
arr[Math.pow(2, 32)] = 'b';

arr.length // 0
arr[-1] // "a"
arr[4294967296] // "b"

上面代碼中塑顺,我們?yōu)閿?shù)組arr添加了兩個不合法的數(shù)字鍵,結(jié)果length屬性沒有發(fā)生變化俏险。這些數(shù)字鍵都變成了字符串鍵名严拒。最后兩行之所以會取到值,是因為取鍵值時竖独,數(shù)字鍵名會默認(rèn)轉(zhuǎn)為字符串裤唠。

in 運算符

檢查某個鍵名是否存在的運算符in,適用于對象预鬓,也適用于數(shù)組巧骚。

var arr = [ 'a', 'b', 'c' ];
2 in arr  // true
'2' in arr // true
4 in arr // false

上面代碼表明,數(shù)組存在鍵名為2的鍵格二。由于鍵名都是字符串劈彪,所以數(shù)值2會自動轉(zhuǎn)成字符串。

注意顶猜,如果數(shù)組的某個位置是空位沧奴,in運算符返回false

var arr = [];
arr[100] = 'a';

100 in arr // true
1 in arr // false

上面代碼中长窄,數(shù)組arr只有一個成員arr[100]滔吠,其他位置的鍵名都會返回false

for…in 循環(huán)和數(shù)組的遍歷

for...in循環(huán)不僅可以遍歷對象挠日,也可以遍歷數(shù)組疮绷,畢竟數(shù)組只是一種特殊對象。

var a = [1, 2, 3];

for (var i in a) {
  console.log(a[i]);
}
// 1
// 2
// 3

但是嚣潜,for...in不僅會遍歷數(shù)組所有的數(shù)字鍵冬骚,還會遍歷非數(shù)字鍵。

var a = [1, 2, 3];
a.foo = true;

for (var key in a) {
  console.log(key);
}
// 0
// 1
// 2
// foo

上面代碼在遍歷數(shù)組時懂算,也遍歷到了非整數(shù)鍵foo只冻。所以,不推薦使用for...in遍歷數(shù)組计技。

數(shù)組的遍歷可以考慮使用for循環(huán)或while循環(huán)喜德。

var a = [1, 2, 3];

// for循環(huán)
for(var i = 0; i < a.length; i++) {
  console.log(a[i]);
}

// while循環(huán)
var i = 0;
while (i < a.length) {
  console.log(a[i]);
  i++;
}

var l = a.length;
while (l--) {
  console.log(a[l]);
}

上面代碼是三種遍歷數(shù)組的寫法。最后一種寫法是逆向遍歷垮媒,即從最后一個元素向第一個元素遍歷舍悯。

數(shù)組的forEach方法航棱,也可以用來遍歷數(shù)組,詳見《標(biāo)準(zhǔn)庫》的 Array 對象一章贱呐。

var colors = ['red', 'green', 'blue'];
colors.forEach(function (color) {
  console.log(color);
});
// red
// green
// blue

數(shù)組的空位

當(dāng)數(shù)組的某個位置是空元素丧诺,即兩個逗號之間沒有任何值,我們稱該數(shù)組存在空位(hole)奄薇。

var a = [1, , 1];
a.length // 3

上面代碼表明,數(shù)組的空位不影響length屬性抗愁。

需要注意的是馁蒂,如果最后一個元素后面有逗號,并不會產(chǎn)生空位蜘腌。也就是說沫屡,有沒有這個逗號,結(jié)果都是一樣的撮珠。

var a = [1, 2, 3,];

a.length // 3
a // [1, 2, 3]

上面代碼中沮脖,數(shù)組最后一個成員后面有一個逗號,這不影響length屬性的值芯急,與沒有這個逗號時效果一樣勺届。

數(shù)組的空位是可以讀取的,返回undefined娶耍。

var a = [, , ,];
a[1] // undefined

使用delete命令刪除一個數(shù)組成員免姿,會形成空位,并且不會影響length屬性榕酒。

var a = [1, 2, 3];
delete a[1];

a[1] // undefined
a.length // 3

上面代碼用delete命令刪除了數(shù)組的第二個元素胚膊,這個位置就形成了空位,但是對length屬性沒有影響想鹰。也就是說紊婉,length屬性不過濾空位。所以辑舷,使用length屬性進(jìn)行數(shù)組遍歷喻犁,一定要非常小心。

數(shù)組的某個位置是空位惩妇,與某個位置是undefined株汉,是不一樣的。如果是空位歌殃,使用數(shù)組的forEach方法乔妈、for...in結(jié)構(gòu)、以及Object.keys方法進(jìn)行遍歷氓皱,空位都會被跳過路召。

var a = [, , ,];

a.forEach(function (x, i) {
  console.log(i + '. ' + x);
})
// 不產(chǎn)生任何輸出

for (var i in a) {
  console.log(i);
}
// 不產(chǎn)生任何輸出

Object.keys(a)
// []

如果某個位置是undefined勃刨,遍歷的時候就不會被跳過。

var a = [undefined, undefined, undefined];

a.forEach(function (x, i) {
  console.log(i + '. ' + x);
});
// 0\. undefined
// 1\. undefined
// 2\. undefined

for (var i in a) {
  console.log(i);
}
// 0
// 1
// 2

Object.keys(a)
// ['0', '1', '2']

這就是說股淡,空位就是數(shù)組沒有這個元素身隐,所以不會被遍歷到,而undefined則表示數(shù)組有這個元素唯灵,值是undefined贾铝,所以遍歷不會跳過。

類似數(shù)組的對象

如果一個對象的所有鍵名都是正整數(shù)或零埠帕,并且有length屬性垢揩,那么這個對象就很像數(shù)組,語法上稱為“類似數(shù)組的對象”(array-like object)敛瓷。

var obj = {
  0: 'a',
  1: 'b',
  2: 'c',
  length: 3
};

obj[0] // 'a'
obj[1] // 'b'
obj.length // 3
obj.push('d') // TypeError: obj.push is not a function

上面代碼中叁巨,對象obj就是一個類似數(shù)組的對象。但是呐籽,“類似數(shù)組的對象”并不是數(shù)組锋勺,因為它們不具備數(shù)組特有的方法。對象obj沒有數(shù)組的push方法狡蝶,使用該方法就會報錯庶橱。

“類似數(shù)組的對象”的根本特征,就是具有length屬性牢酵。只要有length屬性悬包,就可以認(rèn)為這個對象類似于數(shù)組。但是有一個問題馍乙,這種length屬性不是動態(tài)值布近,不會隨著成員的變化而變化。

var obj = {
  length: 0
};
obj[3] = 'd';
obj.length // 0

上面代碼為對象obj添加了一個數(shù)字鍵丝格,但是length屬性沒變撑瞧。這就說明了obj不是數(shù)組。

典型的“類似數(shù)組的對象”是函數(shù)的arguments對象显蝌,以及大多數(shù) DOM 元素集预伺,還有字符串。

// arguments對象
function args() { return arguments }
var arrayLike = args('a', 'b');

arrayLike[0] // 'a'
arrayLike.length // 2
arrayLike instanceof Array // false

// DOM元素集
var elts = document.getElementsByTagName('h3');
elts.length // 3
elts instanceof Array // false

// 字符串
'abc'[1] // 'b'
'abc'.length // 3
'abc' instanceof Array // false

上面代碼包含三個例子曼尊,它們都不是數(shù)組(instanceof運算符返回false)酬诀,但是看上去都非常像數(shù)組。

數(shù)組的slice方法可以將“類似數(shù)組的對象”變成真正的數(shù)組骆撇。

var arr = Array.prototype.slice.call(arrayLike);

除了轉(zhuǎn)為真正的數(shù)組瞒御,“類似數(shù)組的對象”還有一個辦法可以使用數(shù)組的方法,就是通過call()把數(shù)組的方法放到對象上面神郊。

function print(value, index) {
  console.log(index + ' : ' + value);
}

Array.prototype.forEach.call(arrayLike, print);

上面代碼中肴裙,arrayLike代表一個類似數(shù)組的對象趾唱,本來是不可以使用數(shù)組的forEach()方法的,但是通過call()蜻懦,可以把forEach()嫁接到arrayLike上面調(diào)用甜癞。

下面的例子就是通過這種方法,在arguments對象上面調(diào)用forEach方法宛乃。

// forEach 方法
function logArgs() {
  Array.prototype.forEach.call(arguments, function (elem, i) {
    console.log(i + '. ' + elem);
  });
}

// 等同于 for 循環(huán)
function logArgs() {
  for (var i = 0; i < arguments.length; i++) {
    console.log(i + '. ' + arguments[i]);
  }
}

字符串也是類似數(shù)組的對象悠咱,所以也可以用Array.prototype.forEach.call遍歷。

Array.prototype.forEach.call('abc', function (chr) {
  console.log(chr);
});
// a
// b
// c

注意烤惊,這種方法比直接使用數(shù)組原生的forEach要慢乔煞,所以最好還是先將“類似數(shù)組的對象”轉(zhuǎn)為真正的數(shù)組,然后再直接調(diào)用數(shù)組的forEach方法柒室。

var arr = Array.prototype.slice.call('abc');
arr.forEach(function (chr) {
  console.log(chr);
});
// a
// b
// c

參考鏈接

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市逗宜,隨后出現(xiàn)的幾起案子雄右,更是在濱河造成了極大的恐慌,老刑警劉巖纺讲,帶你破解...
    沈念sama閱讀 222,681評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件擂仍,死亡現(xiàn)場離奇詭異,居然都是意外死亡熬甚,警方通過查閱死者的電腦和手機(jī)逢渔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來乡括,“玉大人肃廓,你說我怎么就攤上這事』迕冢” “怎么了盲赊?”我有些...
    開封第一講書人閱讀 169,421評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長敷扫。 經(jīng)常有香客問我哀蘑,道長,這世上最難降的妖魔是什么葵第? 我笑而不...
    開封第一講書人閱讀 60,114評論 1 300
  • 正文 為了忘掉前任绘迁,我火速辦了婚禮,結(jié)果婚禮上卒密,老公的妹妹穿的比我還像新娘缀台。我一直安慰自己,他們只是感情好栅受,可當(dāng)我...
    茶點故事閱讀 69,116評論 6 398
  • 文/花漫 我一把揭開白布将硝。 她就那樣靜靜地躺著恭朗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪依疼。 梳的紋絲不亂的頭發(fā)上痰腮,一...
    開封第一講書人閱讀 52,713評論 1 312
  • 那天,我揣著相機(jī)與錄音律罢,去河邊找鬼膀值。 笑死,一個胖子當(dāng)著我的面吹牛误辑,可吹牛的內(nèi)容都是我干的沧踏。 我是一名探鬼主播,決...
    沈念sama閱讀 41,170評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼巾钉,長吁一口氣:“原來是場噩夢啊……” “哼翘狱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起砰苍,我...
    開封第一講書人閱讀 40,116評論 0 277
  • 序言:老撾萬榮一對情侶失蹤潦匈,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后赚导,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體茬缩,經(jīng)...
    沈念sama閱讀 46,651評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,714評論 3 342
  • 正文 我和宋清朗相戀三年吼旧,在試婚紗的時候發(fā)現(xiàn)自己被綠了凰锡。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,865評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡圈暗,死狀恐怖掂为,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情厂置,我是刑警寧澤菩掏,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站昵济,受9級特大地震影響智绸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜访忿,卻給世界環(huán)境...
    茶點故事閱讀 42,211評論 3 336
  • 文/蒙蒙 一瞧栗、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧海铆,春花似錦迹恐、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽憎茂。三九已至,卻和暖如春锤岸,著一層夾襖步出監(jiān)牢的瞬間竖幔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評論 1 274
  • 我被黑心中介騙來泰國打工是偷, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留拳氢,地道東北人。 一個月前我還...
    沈念sama閱讀 49,299評論 3 379
  • 正文 我出身青樓蛋铆,卻偏偏與公主長得像馋评,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子刺啦,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,870評論 2 361

推薦閱讀更多精彩內(nèi)容