Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/392.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
什么';这是在对象上迭代的最快方式';Javascript中的属性?_Javascript_Performance_Optimization - Fatal编程技术网

什么';这是在对象上迭代的最快方式';Javascript中的属性?

什么';这是在对象上迭代的最快方式';Javascript中的属性?,javascript,performance,optimization,Javascript,Performance,Optimization,我知道我可以像这样迭代对象的属性: for (property in object) { // do stuff } var value = o._hiddenDictionary.lookup('a'); doSomethingWith('a', value); var value = o._hiddenDictionary.lookup('b'); doSomethingWith('b', value); var value = o._hiddenDictionary.lookup

我知道我可以像这样迭代对象的属性:

for (property in object)
{
    // do stuff
}
var value = o._hiddenDictionary.lookup('a');
doSomethingWith('a', value);
var value = o._hiddenDictionary.lookup('b');
doSomethingWith('b', value);
var value = o._hiddenDictionary.lookup('c');
doSomethingWith('c', value);
我还知道,在Javascript中迭代数组的最快方法是使用递减while循环:

var i = myArray.length;
while (i--)
{
    // do stuff fast
}
我想知道是否有类似于递减while循环的东西用于迭代对象的属性


编辑:只需谈谈与可枚举性有关的答案-我不知道

对象的属性按定义是无序的。缺少顺序意味着没有“向前”,因此也没有“向后”。

for/in循环是枚举Javascript对象属性的最佳方式。应该理解的是,这只会循环遍历“可枚举”属性,而不会以特定顺序进行循环。并非所有属性都是可枚举的。通过自己的Javascript代码以编程方式添加的所有属性/方法都是可枚举的,但继承的预定义属性/方法(如
toString
)通常不可枚举

您可以像这样检查可枚举性

var o = new Object();
alert(o.propertyIsEnumerable("toString"));

如果您不知道属性的名称,
for..in
是枚举它们的好方法。如果这样做,最好使用显式取消引用。

1)枚举属性的方法有很多种:

  • (迭代对象及其原型链的可枚举属性)
  • 返回可枚举属性的数组,可直接在对象上找到(不在其原型链中)
  • 返回直接在对象上找到的所有属性(可枚举或不可枚举)的数组
  • 如果您正在处理相同“形状”(属性集)的多个对象,那么“预编译”迭代代码可能是有意义的(请参阅)
  • 不能用于迭代任意对象,但可以与
    映射
    一起使用,这两种方法都适合在某些用例中替代普通对象
也许如果你陈述了你最初的问题,有人可以建议一种优化的方法

2) 我发现很难相信实际的枚举比您对循环体中的属性所做的任何事情都要多

3) 您没有指定要开发的平台。答案可能取决于它,可用的语言特性也取决于它。例如,在2009年前后的SpiderMonkey(Firefox JS解释器)中,如果您实际需要的是值,而不是键,您可以为每个(arr中的var x)使用
()。它比(arr中的vari){varx=arr[i];…}

在某个时刻。下面是一篇关于2017年V8中..in的
内部结构的帖子:

4) 您可能只是没有将其包含在代码段中,但在
迭代中为..执行
的更快方法是确保您在循环中使用的变量在包含循环的函数中声明,即:

//slower
for (property in object) { /* do stuff */ }

//faster
for (var property in object) { /* do stuff */ }

5) 与(4)相关:在尝试优化Firefox扩展时,我曾经注意到将紧循环提取到单独的函数中可以提高其性能()。(显然,这并不意味着您应该总是这样做!)

在JavaScript 1.7+中显式使用
迭代器可能更快或更慢。当然,这只会迭代对象的自己的属性。如果将
ex instanceof StopIteration
替换为
ex==StopIteration
,catch语句也可能更快

var obj = {a:1,b:2,c:3,d:4,e:5,f:6},
   iter = new Iterator(obj, true);

while (true) {
    try {
        doSomethingWithProperty(iter.next());
    } catch (ex if (ex instanceof StopIteration)) {
        break;
    }
}
更新2018/TLDR; 显然,有人把我的想法提升到了一个新的层次,并用它在整个浏览器范围内将“对对象属性求和”的速度提高了100倍以上:

粉红条代表了他的“预编译总和”方法,这使得所有其他方法和操作都束手无策

诀窍是什么?

他的代码是这样的:

var x = 0;
x += o.a;
x += o.b;
x += o.c;
// ...
比这快多了:

var x = 0;
for (var key in o) {
  x += o[key];
}
…尤其是当我们访问属性的顺序(
a
b
c
)与
o
中的顺序匹配时

详细解释如下:

更快的对象属性循环 让我先说,
为。。。在
中循环很好,您只需要在CPU和RAM使用量很大的性能关键型代码中考虑这一点。通常,有更重要的事情你应该花时间在上面。然而,如果你是一个性能怪胎,你可能会对这个近乎完美的选择感兴趣:

Javascript对象 通常,JS对象有两个用例:

  • “字典”,也称为“关联数组”,是具有一组不同属性的通用容器,由字符串键索引
  • “常量类型的对象”(所谓的对象总是相同的)具有固定顺序的固定属性集。是的虽然该标准不保证任何顺序,但现代VM实现都有一个(隐藏的)顺序,以加快速度。正如我们稍后探讨的那样,始终保持这种秩序至关重要
  • 使用“常量类型的对象”而不是“字典类型”通常要快得多,因为优化器了解这些对象的结构。如果您对如何实现这一点感到好奇,那么您可能想了解一下,这一点对于其他Javascript运行时如何使用对象以及如何使用对象有很大的帮助

    在对象的属性上循环 默认的<代码>。。。在
    中迭代对象的所有属性当然是一个不错的选择。但是,
    用于。。。在
    中,可能会将对象视为具有字符串键的字典,即使它具有隐藏类型。在这种情况下,在每一次迭代中,您都会有字典查找的开销,这通常被实现为。在很多情况下,优化器足够聪明,避免了这种情况,性能与您的属性的常量命名一致,但它不能保证。经常
    var value = o._hiddenDictionary.lookup('a');
    doSomethingWith('a', value);
    var value = o._hiddenDictionary.lookup('b');
    doSomethingWith('b', value);
    var value = o._hiddenDictionary.lookup('c');
    doSomethingWith('c', value);
    
    doSomethingWith('a', o.a)
    doSomethingWith('b', o.b)
    doSomethingWith('c', o.c)
    
    //
    // Fast object iterators in JavaScript.
    //
    
    // ########################################################################
    // Type Utilities (define once, then re-use for the life-time of our application)
    // ########################################################################
    
    /**
      * Compiles and returns the "pre-compiled iterator" for any type of given properties.
      */
    var compileIterator = function(typeProperties) {
      // pre-compile constant iteration over object properties
      var iteratorFunStr = '(function(obj, cb) {\n';
      for (var i = 0; i < typeProperties.length; ++i) {
        // call callback on i'th property, passing key and value
        iteratorFunStr += 'cb(\'' + typeProperties[i] + '\', obj.' + typeProperties[i] + ');\n';
      };
      iteratorFunStr += '})';
    
      // actually compile and return the function
      return eval(iteratorFunStr);
    };
    
    // Construct type-information and iterator for a performance-critical type, from an array of property names
    var declareType = function(propertyNamesInOrder) {
      var self = {
        // "type description": listing all properties, in specific order
        propertyNamesInOrder: propertyNamesInOrder,
    
        // compile iterator function for this specific type
        forEach: compileIterator(propertyNamesInOrder),
    
        // create new object with given properties of given order, and matching initial values
        construct: function(initialValues) {
          //var o = { _type: self };     // also store type information?
          var o = {};
          propertyNamesInOrder.forEach((name) => o[name] = initialValues[name]);
          return o;
        }
      };
      return self;
    };
    
    // ########################################################################
    // Declare any amount of types (once per application run)
    // ########################################################################
    
    var MyType = declareType(['a', 'b', 'c']);
    
    
    // ########################################################################
    // Run-time stuff (we might do these things again and again during run-time)
    // ########################################################################
    
    // Object `o` (if not overtly tempered with) will always have the same hidden class, 
    // thereby making life for the optimizer easier:
    var o = MyType.construct({a: 1, b: 5, c: 123});
    
    // Sum over all properties of `o`
    var x = 0;
    MyType.forEach(o, function(key, value) { 
      // console.log([key, value]);
      x += value; 
    });
    console.log(x);
    
    var obj = {a:"a",b:"b"}
    ///{a: "a", b: "b"}
    var keys = Object.getOwnPropertyNames(a)
    ///(2) ["a", "b"]