【问题标题】:Javascript array length incorrect on array of objects对象数组上的Javascript数组长度不正确
【发布时间】:2022-01-14 17:34:13
【问题描述】:

有人能解释一下这种(奇怪的)行为吗?为什么第一个例子中的长度是 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

【问题讨论】:

    标签: javascript arrays


    【解决方案1】:

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

    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”时,您会看到类似的内容。您应该得到类似“[undefined, Object, Object]。因此大小为 3 而不是您预期的 2。

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

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

    这真的意味着:

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

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

    【讨论】:

    • +1 用于解释一个常见的误解。关联数组根本不是数组,它们只是复杂的对象
    • 在 JS 中,数组不一定是连续内存区域意义上的数组,其中索引是从开始的偏移量。但这些细节是不必要的。
    • Object.size = function(obj) { var size = 0, key; for (key in obj) { if (obj.hasOwnProperty(key)) size++; } return size; }; 这将为您提供数组/对象的实际大小。所以你可以调用 Object.size(yourArray) 并且无论你的索引从哪里开始或者键是字符串,它都会给你大小。
    • 虽然 JS 数组的起始索引为 0,但一般情况下并非如此。有些语言以indexing at 1开头,而其他语言允许程序员为每个数组声明起始索引。
    • 在许多 JS 实现中,数组是sparse,因此在设置元素时跳过索引不会设置中间元素。在示例中,a[0] 实际上不会设置为undefinedundefined 是所有未设置索引的返回值。
    【解决方案2】:

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

    a 中最大的键是 2,所以 1+2 是 3。

    b 中没有整数键(其中的键有key1key2,它们不能转换成整数)所以Javascript 假定最大的键是-1,而1 + -1 产生@987654327 @。

    此程序将帮助您了解:

    a = [];
    a["1"] = {};
    a["4"] = {};
    alert(a.length); // Prints 5
    

    【讨论】:

    • 感谢您的回答。我想这是一个“功能”:)。那么,有没有一种方法可以获取数组 b 中的项目数量而无需手动计算它们?或者这是唯一的方法: var len = 0; for (var name in b) len++;
    • 不,这是唯一的方法。 Object 并不是一个真正的关联数组,而是 JavaScript;您可以大部分按原样使用它,但也有陷阱。
    • 对象根本不是数组。之所以会产生混淆,是因为分配属性的一种方法是通过 a[b] 语法......但它与 a.b
    • +1 - 很好的解释。长度属性返回 1 + 最大是有意义的,因为 javascript 的数组被定义为“稀疏”。
    【解决方案3】:

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

    15.4.5.2 长度

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

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

    对于数组,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,你会得到一个带有字符串键"1e+21"的数组,length不受影响。
    • @bobince:1e21 是不同的情况。由于它大于 2**32-1(太大而不能成为 32 位 int),因此它不是数组索引。等价是对称的,所以 'a[3] 等价于 a["3"]' 与 'a[3] 等价于 a["3"]' 的含义相同。我的观点是,将数组索引放在引号中对行为没有影响,而不是元素的名称是整数,就像其他语言一样。我关于自动转换的说法具有误导性;我会重写的。
    • @bobince:我试图忽略实现、模型(如标准中指定)和概念(如何在程序员的头脑中处理一切)之间的差异,这只会使事情复杂化.
    猜你喜欢
    • 1970-01-01
    • 2019-04-23
    • 2017-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-14
    • 1970-01-01
    相关资源
    最近更新 更多