我只是想了解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
循环,我将计算其中有多少属性,而不是它的最后一个索引。 / p>
但如果我尝试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>");
&#13;
答案 0 :(得分:11)
注意:数组索引只是Array对象的属性。
引用MDN的Relationship between length
and numerical properties部分,
当属性是有效的数组索引并且该索引超出数组的当前边界时,在JavaScript数组上设置属性时,引擎将相应地更新数组的
length
属性。
引用ECMA脚本5规范Array Objects,
每当添加名称为数组索引的属性时,如果需要,将更改length属性,使其大于该数组索引的数值;每当更改length属性时,将自动删除名称为数值索引且值不小于新长度的每个属性
因此,当您在索引5
处设置值时,JavaScript引擎会将数组的长度调整为6
。
引用ECMA脚本5规范Array Objects,
当且仅当
P
等于ToString(ToUint32(P))
并且P
不相等时,属性名称ToUint32(P)
(以String值的形式)是一个数组索引到2 32 -1。
因此,在您的情况下,2
和4
是有效索引,但在数组中只定义了2
。您可以像这样确认
arr.hasOwnProperty(2)
其他索引尚未在数组中定义。因此,您的数组对象称为稀疏数组对象。
那么为什么arr [2]被计入for..in循环而不是arr [4]不计算在内?
for..in
枚举对象的所有有效可枚举属性。在您的情况下,由于只有2
是数组中的有效属性,因此将对其进行计数。
但是,当您打印arr[4]
时,它会打印undefined
,因为如果您尝试访问未在对象中定义的属性,JavaScript将返回undefined
。例如,
console.log({}['name']);
// undefined
同样,由于4
尚未定义arr
,因此会返回undefined
。
虽然我们正在讨论这个问题,但您也可能希望阅读这些答案,
答案 1 :(得分:8)
具有值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
只是调整为比你指定的任何索引多一个,如果该索引大于或等于当前长度。
答案 2 :(得分:4)
要从数组中删除undefined
值,请尝试使用.filter()
var arr = [];
arr[5] = "a thing";
arr[2] = undefined;
arr = arr.filter(Boolean);
document.write(arr.length);
答案 3 :(得分:3)
这一切都归结为如何通过机器处理空间。让我们从最简单的想法开始:
var arr =[];
这反过来会创建一个位置,您现在可以在其中存储信息。正如@Mike&#39; Pomax&#39; Kamermans指出:这个位置是一个特殊的javascript对象,它反过来作为键和值的集合,如下所示:
arr[key] = value;
现在继续执行您的代码:
arr[5] = "a thing";
机器现在明白你正在创造一些东西(给予价值)第六个位置 / 第五个键(因为阵列的第一个位置是0)。所以你最终会看到这样的东西:
arr[,,,,,"a thing"];
这些逗号表示数组中的空位(@RobG指出的符号)。
当您声明:
时会发生同样的事情arr[2] = undefined;
arr[,,undefined,,,"a thing"];
因此,当您使用&#34;在&#34;中进行变换时,在数组内部进行迭代您是否正在检查此阵列中已填充的每个空格,因此请依次检查。
作为区别,当您检查数组的长度时,您希望在数组内查看存储信息的空间数,而数组又是6。 / p>
最后,javascript将数组中的空房间解释为未识别的值,这就是arr [4]被输出的原因。
希望能回答你的问题。
答案 4 :(得分:2)
JavaScript数组(至少在第一个版本中)是具有length
属性的普通对象。你经历的大多数奇怪的行为都是这样的结果。
结果有趣,它是6.但它必须包含两个数据,它是如何的 大小可以是6?它可能与我的最新指数有关 在这里使用arr [5] =“一件事”;
导致6
,因为 length
始终比最高索引高1,即使数组中的项目实际上更少。
o为什么arr [2]被计入for..in循环而不是arr [4]不算?
因为当你在做的时候:
arr[2] = undefined;
您实际上是在数组对象中添加了一个名为2
的密钥。因此,值arr[2]
会计入for in
循环,而a[4]
会被忽略。
答案 5 :(得分:0)
赋值设置数组的属性,以便在执行for var i in
样式for循环时,只能看到已设置的属性(即使将它们设置为未定义)。当你分配一个新的integery属性,如arr[6]
时,数组会将数组的长度修改为7.数组中的内存可能会或可能不会相应地重新分配,但是当你去的时候它会在那里使用它 - 除非你的系统内存不足。
根据RobG对ECMA-262所说的评论进行编辑。