繁体   English   中英

数组长度和未定义的索引

[英]Array length and undefined indexes

我只是想了解Javascript数组是如何工作的,但我在这里遇到了一个复杂的问题。

首先我创建了我的数组:

var arr = [];

并在其中设置一些元素:

arr[5] = "a thing";
arr[2] = undefined;

我认为我应该有一个大小为2的数组,因为我在2个特定索引上只有两个对象。 所以我用数组的.length属性测试它:

document.write(arr.length + "<br>");

有趣的是,结果是6.但它必须包含两个项目。 它的大小怎么样? 它可能与我使用的最新指数有关,这里arr[5] = "a thing";

然后我试图循环它:

var size = 0;
for(var x in arr){
 size++;   
}

size变量现在是2.所以,我从中学到了:如果我使用for in循环,我将计算其中有多少属性,而不是它的最后一个索引。

但是如果我尝试使用document.write(arr[4]) (尚未设置),它会写入undefined

那么为什么arr[2]计算在for..in循环中,而不是arr[4]

让我回答一下我的问题:我在想什么类型typeof undefined == undefined这是非常真实的。 但这是JavaScript,我们需要使用自己的规则来玩它:)

jsFiddle和片段如下。

 var arr = []; arr[5] = "a thing"; arr[2] = undefined; document.write(arr.length + "<br>"); var size = 0; for(var x in arr){ size++; } document.write(size + "<br>"); document.write(arr[4] + "<br>"); 

注意:数组索引只是Array对象的属性。

引用MDN的length和数值属性部分之间关系

当属性是有效的数组索引并且该索引超出数组的当前边界时,在JavaScript数组上设置属性时,引擎将相应地更新数组的length属性。

引用ECMA脚本5 数组对象的规范,

每当添加名称为数组索引的属性时,如果需要,将更改length属性,使其大于该数组索引的数值 ; 每当更改length属性时,将自动删除名称为数值索引且值不小于新长度的每个属性

因此,当您在索引5处设置值时,JavaScript引擎会将Array的长度调整为6


引用ECMA脚本5 数组对象的规范,

当且仅当ToString(ToUint32(P))等于PToUint32(P)不等于2 32 -1时,属性名P (以String值的形式)是数组索引。

因此,在您的情况下, 24是有效索引,但在数组中只定义了2 你可以这样确认

arr.hasOwnProperty(2)

其他索引尚未在数组中定义。 因此,您的数组对象称为稀疏数组对象

那么为什么arr [2]被计入for..in循环而不是arr [4]不算?

for..in枚举对象的所有有效可枚举属性。 在您的情况下,由于数组中只有2是有效属性,因此将对其进行计数。

但是,当您打印arr[4] ,它会打印undefined ,因为如果您尝试访问未在对象中定义的属性,JavaScript将返回undefined 例如,

console.log({}['name']);
// undefined

类似地,由于arr尚未定义4 ,因此返回undefined


虽然我们是关于这个主题的,但您也可能想要阅读这些答案,

具有undefined值的属性与不存在的属性之间存在差异,此处使用in运算符说明:

var obj = {
    one: undefined
};

console.log(obj.one === undefined); // true
console.log(obj.two === undefined); // true

console.log('one' in obj); // true
console.log('two' in obj); // false

当您尝试获取不存在的属性的值时,仍然会undefined ,但这不会使其存在。

最后,为了解释你看到的行为: for in循环只会遍历那个键in对象中的键(并且是可枚举的)。

同时,如果该索引大于或等于当前长度,则仅将length调整为比指定的索引多一个。

要从数组中删除undefined值,请尝试使用.filter()

 var arr = []; arr[5] = "a thing"; arr[2] = undefined; arr = arr.filter(Boolean); document.write(arr.length); 

这一切都归结为如何通过机器处理空间。 让我们从最简单的想法开始:

var arr =[];

这反过来又创造了,你现在可以存储信息的位置 正如@Mike'Pomax'Kamermans指出的那样:这个位置是一个特殊的javascript对象,它反过来作为键和值的集合,如下所示:

arr[key] = value;

现在继续你的代码:

arr[5] = "a thing";

机器现在知道你正在创建第6个位置 / 第5个键的值(给出值)(因为数组的第一个位置是0)。 所以你结束了这样的事情:

arr[,,,,,"a thing"];

这些逗号代表数组中的空位(@RobG指出的符号)。

当你声明时,会发生同样的事情:

arr[2] = undefined;
arr[,,undefined,,,"a thing"];

因此,当您使用“for var in”在数组内部进行迭代时,您将检查此数组中已填充的每个空格,因此依次为2。

不同的是,当您检查数组的长度时,您正在查看数组内部存储信息的空间数 ,而后者又是6。

最后,javascript将数组中的空房间解释为未识别的值,这就是arr [4]被输出的原因。

希望能回答你的问题。

JavaScript数组(至少在第一个版本中)是具有length属性的普通对象。 你经历的大多数奇怪的行为都是这样的结果。

结果有趣,它是6.但它必须包含两个数据,它的大小如何可以是6? 它可能与我在这里使用的最新索引有关[5] =“一件事”;

它导致6因为length总是比最高索引高1,即使数组中的项目实际上更少。

o为什么arr [2]被计入for..in循环而不是arr [4]不算?

因为你在做的时候:

arr[2] = undefined;

实际上,您正在向数组对象添加一个名为2的键。 结果,值arr[2]for in循环中计数,而a[4]被忽略。

赋值设置数组的属性,因此当您for var i in for循环中执行for var i in ,只能看到已设置的属性(即使您将它们设置为未定义)。 当你分配一个新的integery属性,比如arr[6] ,数组会将数组的长度修改为7.数组中的内存可能会或者可能不会相应地重新分配,但是当你去使用它时它会在那里它 - 除非你的系统内存不足。

根据RobG对ECMA-262所说的评论进行了编辑。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM