【Dmitri Pavlutin】數組長度屬性背後的魔法

翻譯:道奇
做者:Dmitri Pavlutin
原文:The Magic Behind Array Length Property數組

開發人員天天都會處理數組,做爲一個集合,它有一個很重要的用於查詢的屬性是項(item)的數量:Array.prototype.length安全

在JavaScript中,length並不老是指的現有元素(對於稀疏矩陣)的數量,修改屬性也可能會移除元素。bash

下面讓咱們揭開這個屬性背後魔法的面紗。app

"數組length是一個無符號的32位整數,其數值大於數組中索引的最大值"函數

這個屬性根據所指定的數組類型不一樣行爲也不一樣,下面列舉他們:當數組的元素的索引是連續的且從0開始,數組就是密集(dense)的,例如[1, 3, 4]是密集的,由於索引是連續的:0, 12。當數組的元素不是從0開始的連續索引,那麼它就是稀疏(sparse)的,例如[1, ,4, 6]是稀疏的,由於元素的索引是不連續的:0, 23ui

Length做爲數組元素的數量

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比最大索引大,可是它並不表明真實的元素數量。當查詢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修改

在上述的分析中,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()方法。

相關文章
相關標籤/搜索