【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()方法。

相关文章
相关标签/搜索