翻譯:道奇
做者:Dmitri Pavlutin
原文:The Magic Behind Array Length Property數組
開發人員天天都會處理數組,做爲一個集合,它有一個很重要的用於查詢的屬性是項(item)的數量:Array.prototype.length
。安全
在JavaScript中,length
並不老是指的現有元素(對於稀疏矩陣)的數量,修改屬性也可能會移除元素。bash
下面讓咱們揭開這個屬性背後魔法的面紗。app
"數組
length
是一個無符號的32
位整數,其數值大於數組中索引的最大值"函數
這個屬性根據所指定的數組類型不一樣行爲也不一樣,下面列舉他們:當數組的元素的索引是連續的且從0
開始,數組就是密集(dense
)的,例如[1, 3, 4]
是密集的,由於索引是連續的:0
, 1
和2
。當數組的元素不是從0
開始的連續索引,那麼它就是稀疏(sparse
)的,例如[1, ,4, 6]
是稀疏的,由於元素的索引是不連續的:0
, 2
和3
。ui
length
經常使用的就是肯定元素的數量,這在密集的集合類型下是正確的:spa
var fruits = ['orange', 'apple', 'banana']; //fruits密集數組
fruits.length // 打印3, 實際的元素數量
fruits.push('mango');
fruits.length // 打印4, 添加了一個元素
var empty = [];
empty.length // 打印 0, 空數組
複製代碼
能夠在JS Bin中看這個例子prototype
密集數組沒有空槽的數組元素,元素的數量至關於最大索引值 + 1
,在[3, 5, 7, 8]
中最大的索引是元素8
的索引3
,所以數組的大小是3 + 1 = 4
。翻譯
在稀疏數組中,length
比最大索引大,可是它並不表明真實的元素數量。當查詢length
,它比元素的總數大。這是由於數組中存在空槽位置的緣由。code
var animals = ['cat', 'dog', , 'monkey']; // animals是稀疏的
animals.length // 打印 4,可是實際數量是3
var words = ['hello'];
words[6] = 'welcome'; //最大的索引是6,words是稀疏數組
words.length //打印 7, 基於最大索引
複製代碼
當添加或移除元素時,length
僅會根據最大索引進行改變,任何不會影響數組最大索引的修改都不會影響length
,例如,使用delete
。
var colors = ['blue', 'red', 'yellow', 'white', 'black'];
colors.length // 打印5
delete colors[0]; // 移除第一個元素 'blue'
// 數組變成稀疏數組
colors.length // 依然打印5,由於最高的索引是4 ,沒有發生改變
複製代碼
能夠在JS Bin中看這個例子
在上述的分析中,length
是隻讀的。可是JavaScript容許修改這個屬性,length
的修改會怎樣影響數組取決於新的值和現有的最大的索引,這個操做也能夠移除元素或使數組變成稀疏數組。當新的length
值小於或等於最大索引時,任何元素,若是它的索引大於或等於新組大小就會被移除,這種作法的一個有用的場景就是移除數組的最後一個元素。
var numbers = [1, 3, 5, 7, 8];
numbers.length = 3; // 修改數組length
numbers // 打印 [1, 3, 5], 元素7和8被移除
複製代碼
若是使用大於最大索引(或使用大於當前length
的數值)的數值,數組就會變成稀疏的,這個用處不大。
var osTypes = ['OS X', 'Linux', 'Windows'];
osTypes.length = 5; // 建立一個稀疏數組,索引索引3和4的元素不存在
osTypes // 打印 ['OS X', 'Linux', 'Windows', undefined,undefined ]
複製代碼
能夠在JS Bin中看這個例子
給length
指定數字以外的類型也是能夠的,JavaScript會將這個原始值轉換爲數字,若是轉換的結果是NAN
或是小於0
的數字,就會拋出沒有捕捉的範圍異常:元素數組長度
var numbers = [1, 4, 6, 7];
numbers.length = '2'; // '2'被轉換爲數字 2
numbers.length = 'not-number'; // 拋出沒有捕捉的範圍異常:元素數組長度
numbers.length = -2; // 拋出沒有捕捉的範圍異常:元素數組長度
複製代碼
修改數組length
,經過delete
移除元素,使用[新索引]
添加元素都是經過建立稀疏數組而產生潛在問題的根源。結果是length
值不一致,JavaScript提供了更安全的替代方案。
使用Array.prototype.push()
向數組末尾添加元素,經過pop()
移除最後一個元素 ,使用unshift()
向數組起始端插入元素和使用shift()
移除第一個元素。對於更復雜的插入、刪除或替換,splice()
是足夠強大的。
var companies = ['Apple', 'Dell'];
companies.push('ASUS'); // 向末尾添加元素
companies // 打印 ['Apple', 'Dell', 'ASUS']
companies.pop(); // 打印 "ASUS". 移除最後一個元素
companies // 打印 ['Apple', 'Dell']
companies.shift(); // 打印 "Apple". 移除第一個元素
companies // 打印 ["Dell"]
companies.splice(1, 0, "Microsoft", "HP"); // 添加兩空公司
companies // 打印 ["Dell", "Microsoft", "HP"]
companies.length // 打印 3. 數組是密集的
複製代碼
能夠在JS Bin中看這個例子
在極少數狀況下,數組多是稀疏的。靠length
決定元素的數量是不安全的,能夠使用一個幫助函數來處理缺乏的元素:
/**
* 計算一個稀疏數組的元素數量
* @param {Array} collection
* @return {number}
*/
function count(collection) {
var totalCount = 0;
for (var index = 0; index < collection.length; index++) {
if (index in collection) {
totalCount++;
}
}
return totalCount;
}
複製代碼
in
運算符能夠用於判斷這個對象是否有屬性,它在檢查元素在指定的索引下是否存在是很是有用的。
就像在這篇文章中看到的,length
是一個具備複雜行爲的屬性。 大部分狀況下,都能正常工做,可是當處理稀疏數組並修改length
時最好當心一點。 另外一種方法是徹底避免修改此屬性並使用splice()
方法。