元素按“ for(…in…)”循环排序

2020/10/16 06:21 · javascript ·  · 0评论

Javascript中的“ for…in”循环是否按声明的顺序遍历哈希表/元素?有没有按顺序执行的浏览器?

我希望使用的对象将被声明
一次,并且永远不会被修改。

假设我有:

var myObject = { A: "Hello", B: "World" };

我进一步将它们用于:

for (var item in myObject) alert(item + " : " + myObject[item]);

我是否可以期望在大多数体面的浏览器中,“ A:“ Hello””总是排在“ B:“ World””之前?

引用John Resig

当前,所有主流浏览器都按照定义它们的顺序遍历对象的属性。Chrome可以做到这一点,除了少数情况。[...] ECMAScript规范明确未定义此行为。在ECMA-262中,第12.6.4节:

枚举属性的机制...取决于实现。

但是,规范与实现完全不同。ECMAScript的所有现代实现都按照定义它们的顺序遍历对象属性。因此,Chrome小组认为这是一个错误,并将予以修复。

除Chrome和Opera以外,所有浏览器都遵循定义顺序,而Chrome和Opera则针对每个非数字属性名称。在这两种浏览器中,属性是按顺序拉到第一个非数字属性之前的(这与它们实现数组的方式有关)。顺序也相同Object.keys

该示例应清楚说明发生了什么:

var obj = {
  "first":"first",
  "2":"2",
  "34":"34",
  "1":"1",
  "second":"second"
};
for (var i in obj) { console.log(i); };
// Order listed:
// "1"
// "2"
// "34"
// "first"
// "second"

它的技术性不如可能随时更改的事实重要。不要依赖保持这种状态的事物。

简而言之:如果顺序对您很重要,请使用数组。

一年后撞到这个...

现在是2012年,主要的浏览器仍然不同:

function lineate(obj){
    var arr = [], i;
    for (i in obj) arr.push([i,obj[i]].join(':'));
    console.log(arr);
}
var obj = { a:1, b:2, c:3, "123":'xyz' };
/* log1 */  lineate(obj);
obj.a = 4;
/* log2 */  lineate(obj);
delete obj.a;
obj.a = 4;
/* log3 */  lineate(obj);

要点在当前浏览器中进行测试

Safari 5,Firefox 14

["a:1", "b:2", "c:3", "123:xyz"]
["a:4", "b:2", "c:3", "123:xyz"]
["b:2", "c:3", "123:xyz", "a:4"]

Chrome 21,Opera 12,Node 0.6,Firefox 27

["123:xyz", "a:1", "b:2", "c:3"]
["123:xyz", "a:4", "b:2", "c:3"]
["123:xyz", "b:2", "c:3", "a:4"]

IE9

[123:xyz,a:1,b:2,c:3] 
[123:xyz,a:4,b:2,c:3] 
[123:xyz,a:4,b:2,c:3] 

ECMAScript语言规范的12.6.4节(for .. in循环中):

枚举属性的机制取决于实现。枚举的顺序由对象定义。

和第4.3.3节(“对象”的定义):

它是属性的无序集合,每个属性都包含原始值,对象或函数。存储在对象属性中的函数称为方法。

我想这意味着您不能依赖JavaScript实现中以一致顺序枚举的属性。(无论如何,依赖于特定于实现的语言细节都是不好的风格。)

如果要定义订单,则需要实现一些定义它的东西,例如在访问带有该对象的对象之前对键进行排序的数组。

用于枚举/枚举的对象的元素是未设置DontEnum标志的属性。ECMAScript(又名Javascript)标准明确表示“对象是属性的无序集合”(请参见http://www.mozilla.org/js/language/E262-3.pdf第8.6节)。

假定所有Javascript实现将按声明顺序枚举并不是符合标准(即安全)的。

迭代顺序在删除属性方面也很混乱,但是在这种情况下,仅使用IE。

var obj = {};
obj.a = 'a';
obj.b = 'b';
obj.c = 'c';

// IE allows the value to be deleted...
delete obj.b;

// ...but remembers the old position if it is added back later
obj.b = 'bb';
for (var p in obj) {
    alert(obj[p]); // in IE, will be a, bb, then c;
                   // not a, c, then bb as for FF/Chrome/Opera/Safari
}

如果http://code.google.com/p/v8/issues/detail?id=164的讨论有任何迹象,那么更改规范以固定迭代顺序的愿望似乎在开发人员中非常普遍

在IE6中,无法保证顺序。

该订单不能被信任。Opera和Chrome均返回无序的属性列表。

<script type="text/javascript">
var username = {"14719":"A","648":"B","15185":"C"};

for (var i in username) {
  window.alert(i + ' => ' + username[i]);
}
</script>

上面的代码显示Opera中的B,A,C和Chrome中的C,A,B。

这本身并不能回答问题,但是可以为基本问题提供解决方案。

假设您不能依赖于保留顺序,为什么不使用键和值作为属性的对象数组呢?

var myArray = [
    {
        'key'   : 'key1'
        'value' : 0
    },
    {
        'key'   : 'key2',
        'value' : 1
    } // ...
];

现在,由您来确保键是唯一的(假设这对您也很重要。此外,直接寻址更改,并且for(... in ...)现在将索引作为“键”返回。

> console.log(myArray[0].key);
key1

> for (let index in myArray) {console.log(myArray[index].value);}
0
1

有关CodePenJDQ@JDQ)的顺序请参见笔中的(... in ...)寻址

如其他答案所述,不,不能保证顺序。

如果要按顺序进行迭代,可以执行以下操作:

let keys = Object.keys(myObject);
for (let key of keys.sort()) {
  let value = myObject[key];
  
  // Do what you want with key and value 
}

请注意,从性能角度来看,这并不是最佳选择,但是这是您想要漂亮的字母显示时的价格。

本文地址:http://javascript.askforanswer.com/yuansuan-forinxunhuanpaixu.html
文章标签: ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!