【发布时间】:2019-12-19 10:33:05
【问题描述】:
我需要遍历一个 JavaScript 对象,将其视为具有自定义键的数组。 我知道这不是完全支持的,因为属性没有内在顺序,但由于我总是重新排序属性,我发现这种方法简单可靠......直到现在。
当键是数字或可以转换为数字的字符串时会出现问题。
当我运行这段代码时:
var test1 = {4294966222:"A",4294966333:"A",4294966111:"A"};
var test2 = {4294968222:"A",4294968333:"A",4294968111:"A"};
for (var k in test1) {console.log(k);}
console.log("---");
for (var k in test2) {console.log(k);}
输出是:
4294966111
4294966222
4294966333
---
4294968222
4294968333
4294968111
这意味着:
- (test1) 如果键值低于 2^32 (4,294,967,296),它们会自动重新排序,最小的在前
- (test2) 如果键值高于 2^32,则不会重新排序。
问题是:为什么会这样?
由于我测试的所有浏览器(Google Chrome 79.0、Mozilla Firefox 71.0、Microsoft Edge 44.18362、Internet Explorer 11.535)都同意此输出,因此必须有一些官方规范。
更新
在发现这是一个门槛问题之前,我测试了很多数字。我发现序列 2,3,1 与以相同方式排序的三个时间戳的行为不同。
【问题讨论】:
-
我的猜测是哈希码是如何计算的,但这不是您问题的真正答案。
-
我不认为它在真正的口语意义上被破坏了,他们不保证这些值会按顺序迭代,因为它是任意运行的,你可以检查developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…"注意: for...in 不应该用于遍历索引顺序很重要的数组。”它们只保证对集合中的每个元素进行迭代。像 forEach 这样的东西确实通过按升序遍历项目来考虑顺序ecma-international.org/ecma-262/5.1/#sec-15.4.4.18
-
记录一下,直接登录
test1和test2就可以看到问题了。我认为“问题”来自规范的 V8 实现中的密钥缓存。 -
更多的是,在 2^32 以下,您的属性名称是巧合地排序,类似于内部属性引用。您可以而且不应该依赖对象属性的顺序,因为根据定义它们没有顺序并且可以包含对象固有的属性。始终将您的对象转换/映射到数组中,对数组进行排序,然后在顺序很重要时循环遍历它。
-
@Mr.Toxy 那是因为
4294968333和4294968111的属性大于2 ** 32(即4294967296)。因此,它们不是数组索引,因此它们按属性创建顺序进行迭代,而不是按数字升序进行迭代——这正是它们在小提琴中所做的,正如预期的那样。 (见我的回答)
标签: javascript