对象数组上的Javascript数组长度不正确

IT技术 javascript arrays
2021-02-19 06:10:00

有人可以解释这种(奇怪的)行为吗?为什么第一个例子中的长度是 3 而不是 2,最重要的是,为什么第二个例子中的长度是 0?只要键是数字的,长度就有效。如果不是,则长度为 0。如何从第二个示例中获得正确的长度?谢谢你。

a = [];
a["1"] = {"string1":"string","string2":"string"};
a["2"] = {"string1":"string","string2":"string"};
alert(a.length); // returns 3

b = [];
b["key1"] = {"string1":"string","string2":"string"};
b["key2"] = {"string1":"string","string2":"string"};
alert(b.length); // returns 0
3个回答

需要注意的一件事是常规数组和关联数组之间存在差异。在常规数组(真实数组)中,索引必须是整数。另一方面,关联数组可以使用字符串作为索引。如果您愿意,您可以将关联数组视为地图。现在,还要注意,真正的数组总是从零开始。因此,在您的示例中,您按以下方式创建了一个数组:

a = [];
a["1"] = {"string1":"string","string2":"string"};
a["2"] = {"string1":"string","string2":"string"}

Javascript 能够将您的字符串索引转换为数字,因此,您上面的代码变为:

a = [];
a[1] = {"blah"};
a[2] = {"blah"};

但请记住我之前说过的话:真正的数组从零开始。因此,javascript 解释器会自动将 a[0] 分配给 undefined。在 firebug 或 chrome/safari 控制台中尝试一下,当您尝试打印“a”时,您会看到类似的内容。您应该得到类似“[未定义,对象,对象]。因此,大小为 3,而不是您预期的 2。

在您的第二个示例中,我很确定您正在尝试模拟关联数组的使用,这实质上是向对象添加属性。记住关联数组使您能够使用字符串作为键。因此,换句话说,您正在向对象添加一个属性。所以在你的例子中:

b["key1"] = {"string1":"string","string2":"string"};

这真的意味着:

b.key1 = {"string1":"string","string2":"string"};

初始化 b =[] 只是创建一个数组,但您的赋值不会填充该数组。它只是给“b”额外的属性。希望这可以帮助.. :-)

Object.size = function(obj) { var size = 0, key; for (key in obj) { if (obj.hasOwnProperty(key)) size++; } return size; }; 这将使您获得数组/对象的实际大小。所以你可以只调用 Object.size(yourArray) ,无论你的索引从哪里开始或者键是字符串,它都会给你大小。
2021-04-20 06:10:00
在许多 JS 实现中,数组是sparse,因此在设置元素时跳过索引不会设置中间元素。在示例中,a[0]实际上不会设置为undefined; undefined是为所有未设置的索引返回的内容。
2021-04-26 06:10:00
+1 用于解释一个常见的误解。关联数组根本不是数组,它们只是复杂的对象
2021-04-27 06:10:00
虽然 JS 数组的起始索引是 0,但通常情况并非如此。一些语言从1开始索引,而其他语言允许程序员声明每个数组的起始索引。
2021-04-28 06:10:00
在 JS 中,数组甚至不一定是连续内存区域意义上的数组,其中索引是从开始的偏移量。但这些细节是不必要的。
2021-05-03 06:10:00

length 返回 1 + 对象中最大的整数键。

a最大关键是2所以1 + 2是3。

b没有整数键(键有key1key2不能被转换成整数)这样的Javascript假定最大关键是-1,和1 + -1产量0

该程序将帮助您了解:

a = [];
a["1"] = {};
a["4"] = {};
alert(a.length); // Prints 5
对象根本不是数组。之所以混淆是因为分配属性的一种方法是通过 a[b] 语法……但它与说 ab 没有什么不同
2021-05-04 06:10:00
不,这是唯一的办法。Object不是真正合适的关联数组是 JavaScript;大多数情况下,您可以像使用它一样使用它,但也存在缺陷。
2021-05-09 06:10:00
+1 - 很好的解释。长度属性返回 1 + 最大是有道理的,因为 javascript 的数组被定义为“稀疏”。
2021-05-12 06:10:00
谢谢您的回答。我想这是一个“功能”:)。那么,有没有办法获得数组 b 中的项目数量而无需手动计算它们?或者这是唯一的方法:var len = 0; for (var name in b) len++;
2021-05-13 06:10:00

来自 ECMAScript 标准,ECMA-262,第 5 版。

15.4.5.2 长度

此 Array 对象的 length 属性是一个数据属性,其值在数字上始终大于名称为数组索引的每个可删除属性的名称。

注意数组的长度属性只考虑数组索引,它们是整数;设置其他属性不会影响长度。

对于数组,a["3"]等效于a[3](此行为由第 15.4.5.1 节指定);3 是数组索引而不是属性。因此设置a["3"]会影响数组的长度。b["key1"]相当于b.key1设置属性不会影响集合的长度。

实际上a[3]正好相反:所有的键都是字符串,所以等价于a["3"]. 如果你说for (i in array)i"3"和不会3写入a[1000000000000000000000]= true,您将拥有一个带有字符串 key 的数组"1e+21"length不受影响。
2021-04-22 06:10:00
@bobince:1e21 是另一种情况。由于它大于 2**32-1(太大而不能成为 32 位 int),因此它不是数组索引。等价是对称的,所以 'a[3] 等价于 a["3"]' 和 'a[3] 等价于 a["3"]' 说的一样。我的观点是,将数组索引放在引号中对行为没有影响,而不是元素的名称是整数,就像其他语言一样。我关于自动转换的陈述具有误导性;我会重写那个。
2021-05-06 06:10:00
@bobince:我试图忽略实现、模型(如标准中指定的)和概念(如何在程序员的头脑中处理一切)之间的差异,这只会使问题复杂化。
2021-05-15 06:10:00