[英]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))
等于P
且ToUint32(P)
不等于2 32 -1时,属性名P
(以String值的形式)是数组索引。
因此,在您的情况下, 2
和4
是有效索引,但在数组中只定义了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.