我需要遍历一个 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);}Run Code Online (Sandbox Code Playgroud)
输出是:
4294966111
4294966222
4294966333
---
4294968222
4294968333
4294968111
Run Code Online (Sandbox Code Playgroud)
意思是:
问题是:为什么会发生这种情况?
由于我测试的所有浏览器(Google Chrome 79.0、Mozilla Firefox 71.0、Microsoft Edge 44.18362、Internet Explorer 11.535)都同意此输出,因此必须有一些官方规范。
在发现这是一个门槛问题之前,我测试了很多数字。我发现奇怪的是,序列 2,3,1 的行为与以相同方式排序的三个时间戳不同。
这是预料之中的。根据规范,迭代属性的方法OrdinaryOwnPropertyKeys执行以下操作:
\n\n\n\n
\n- \n
对于作为数组索引的O 的每个自己的属性键 P ,按升序数字索引顺序,执行
\n\nA。添加 P 作为键的最后一个元素。
- \n
对于 O 的每个自己的属性键 P(它是字符串但不是数组索引),按照属性创建的升序时间顺序,执行以下操作:
\n\nA。添加 P 作为键的最后一个元素。
升序数字顺序仅适用于作为数组索引的属性。
\n\n那么,什么是“数组索引”?查一下::
\n\n\n\n\n整数索引是一个字符串值属性键,它是一个规范的数字字符串(请参阅 7.1.21),其数值为 +0 或正整数 \xe2\x89\xa4 2^53 - 1。数组索引为一个整数索引,其数值 i 的范围为 +0 \xe2\x89\xa4 i < 2^32 - 1。
\n
因此,大于 2^32 的数字属性不是数组索引,因此按照属性创建的顺序进行迭代。但是,小于的数字属性2^32 是数组索引,并且按升序数字顺序迭代。
因此,例如:
\n\n1:数组索引,将按数字进行迭代
10:数组索引,将按数字进行迭代
4294968111:大于,将在数组索引完成后2 ** 32按照属性创建顺序进行迭代
9999999999999:大于,将在数组索引完成后2 ** 32按照属性创建顺序进行迭代
另外,请记住,与普遍的看法相反,由于第四阶段的for-in 迭代提案,属性迭代顺序也由规范保证。
\n