for..in 循环是否跟踪对象的属性顺序?

Does for..in loop keeps track of orders of its properties for Object?

我是编程的初学者,JavaScript 是我的第一语言。我在读书的时候遇到了这个顾虑,不知道自己的顾虑对不对。

我认为 for..in 当我们循环遍历对象时,循环不会跟踪顺序,因为与数组不同,对象的属性不是基于索引的。

这让我质疑我从 Underscore.js 重新创建一些方法的工作,例如 _.each_.reduce

以下是我重新创建这些方法的尝试。

var each = function(list, iteratee) {
    if (Array.isArray(list)) {
        for (var i = 0; i < list.length; i++) {
            iteratee(list[i], i, list);
        }
    } else if (list.constructor === Object) {
        for (var key in list) {
            iteratee(list[key], key, list);
        }
    }
};

var reduce = function(list, iteratee, memo){  
  var memoUndefined = arguments.length < 3;
  each(list, function(elem, index, list){
    if (memoUndefined) {
      memoUndefined = false;
      memo = elem;
    } else {
        memo = iteratee(memo, elem, index, list);
    }
  });
  return memo;
};

它们似乎可以正常工作,因此可以像 list 一样在 Array 和 Object 上工作,无论是否提供 memo

但是,让我感到疑惑的是,我的 each 函数如何跟踪它正在迭代的属性的顺序?它如何确保被循环的属性的顺序始终一致?它对数组有意义,因为它的属性是索引。但对象不是。我相信这在像我上面的 reduce 这样的函数中实现时可能会有潜在的问题。如果 iteratee 将来做的只是简单的加法或减法,那可能没问题,但是乘法或除法呢?值 each 将迭代的顺序将是至关重要的。我的担心合适吗?

ECMAScript ES5 规范特别指出 for/in 循环不保证属性的顺序。来自 ES5 规范中的section 12.6.4

The mechanics and order of enumerating the properties (step 6.a in the first algorithm, step 7.a in the second) is not specified.

不过,在大多数 ES5 浏览器实现中,属性是按照它们创建的顺序迭代的。

我读到有人建议将 for/in 的属性顺序记录为新兴 ES6 规范中创建的顺序。

我在ES6草案中没有找到这个具体的写法,但是有关于Object.keys()的注释:

If an implementation defines a specific order of enumeration for the for-in statement, the same order must be used for the elements of the array returned in step 4.

请记住,即使顺序始终是特定方式,也没有修改顺序的功能。因此,如果您真的关心属性的顺序,那么对象上的 for/in 循环可能并不是 store/access 一组有序属性的正确方法。