【问题标题】:Iterate over object keys in node.js迭代 node.js 中的对象键
【发布时间】:2011-11-18 09:26:53
【问题描述】:

从 Javascript 1.7 开始,有一个 Iterator 对象,它允许这样做:

var a={a:1,b:2,c:3};
var it=Iterator(a);

function iterate(){
    try {  
        console.log(it.next());
        setTimeout(iterate,1000);
    }catch (err if err instanceof StopIteration) {  
        console.log("End of record.\n");  
    } catch (err) {  
        console.log("Unknown error: " + err.description + "\n");  
    }  

}
iterate();

node.js 中有这样的东西吗?

我现在正在使用:

function Iterator(o){
    /*var k=[];
    for(var i in o){
        k.push(i);
    }*/
    var k=Object.keys(o);
    return {
        next:function(){
            return k.shift();
        }
    };
}

但是通过将所有对象键存储在k 中会产生大量开销。

【问题讨论】:

  • 什么开销?你有多少键和迭代器?如果他们的产品少于 100 万,请忽略这种“低效率”。
  • @jcolebrand φ:似乎createNodeIterator 是用于 DOM 元素的,我什至没有 DOM ;) @c69:我将所有数据存储在对象的 keys 和 @ 987654328@ 刚刚设置为1(700k 密钥中大约 20MB),事实上,现在我只是忽略了这个“开销”,但我更喜欢更好的解决方案:)
  • 我把它看成是一个可以搞乱的类;-)

标签: javascript node.js iterator


【解决方案1】:

您想要的是对对象或数组的惰性迭代。这在 ES5 中是不可能的(因此在 node.js 中是不可能的)。我们最终会得到这个。

唯一的解决方案是找到一个扩展 V8 的节点模块来实现迭代器(可能还有生成器)。我找不到任何实现。您可以查看 spidermonkey 源代码并尝试使用 C++ 将其编写为 V8 扩展。

您可以尝试以下方法,但它也会将所有键加载到内存中

Object.keys(o).forEach(function(key) {
  var val = o[key];
  logic();
});

但是,由于Object.keys 是一种本机方法,它可能会进行更好的优化。

Benchmark

如您所见,Object.keys 明显更快。实际的内存存储是否更优化是另一回事。

var async = {};
async.forEach = function(o, cb) {
  var counter = 0,
    keys = Object.keys(o),
    len = keys.length;
  var next = function() {
    if (counter < len) cb(o[keys[counter++]], next);
  };
  next();
};

async.forEach(obj, function(val, next) {
  // do things
  setTimeout(next, 100);
});

【讨论】:

  • 谢谢!,这稍微改进了我的迭代器:)(更新了代码)但遗憾的是内存问题仍然存在:(而且我不能使用forEach,因为每个迭代步骤都应该从异步调用setTimeout.
  • @stewe 添加了async.forEach
  • 感谢您的澄清!我可能会尝试 c++ 扩展方法。
  • @stewe 如果你设法编写它,请将其发布在 github 上并在此处的答案或评论中留下指向它的链接 o/
  • @stewe 关于那个 C++ 扩展,是你创作的吗?
【解决方案2】:

还请记住,您可以将第二个参数传递给.forEach() 函数,指定要用作this 关键字的对象。

// myOjbect is the object you want to iterate.
// Notice the second argument (secondArg) we passed to .forEach.
Object.keys(myObject).forEach(function(element, key, _array) {
  // element is the name of the key.
  // key is just a numerical value for the array
  // _array is the array of all the keys

  // this keyword = secondArg
  this.foo;
  this.bar();
}, secondArg);

【讨论】:

  • 对线程的补充很好,但是......为什么将传递的对象的键显示为称为“元素”的东西,而键数组的枚举器称为“键”?!我可以建议您更新您的代码示例以使用Object.keys(myObject).forEach(function(key, index, arrayOfKeys) {
【解决方案3】:

调整他的代码:

Object.prototype.each = function(iterateFunc) {
        var counter = 0,
keys = Object.keys(this),
currentKey,
len = keys.length;
        var that = this;
        var next = function() {

            if (counter < len) {
                currentKey = keys[counter++];
                iterateFunc(currentKey, that[currentKey]);

                next();
            } else {
                that = counter = keys = currentKey = len = next = undefined;
            }
        };
        next();
    };

    ({ property1: 'sdsfs', property2: 'chat' }).each(function(key, val) {
        // do things
        console.log(key);
    });

【讨论】:

    【解决方案4】:

    我是 node.js 的新手(大约 2 周),但我刚刚创建了一个模块,它以递归方式向控制台报告对象的内容。它将列出所有项目或搜索特定项目,然后根据需要向下钻取给定的深度。

    也许您可以自定义它以满足您的需求。把事情简单化!为什么复杂?...

    'use strict';
    
    //console.log("START: AFutils");
    
    // Recusive console output report of an Object
    // Use this as AFutils.reportObject(req, "", 1, 3); // To list all items in req object by 3 levels
    // Use this as AFutils.reportObject(req, "headers", 1, 10); // To find "headers" item and then list by 10 levels
    // yes, I'm OLD School!  I like to see the scope start AND end!!!  :-P
    exports.reportObject = function(obj, key, level, deep) 
    {
        if (!obj)
        { 
            return;
        }
    
        var nextLevel = level + 1;
    
        var keys, typer, prop;
        if(key != "")
        {   // requested field
            keys = key.split(']').join('').split('[');
        }
        else
        {   // do for all
            keys = Object.keys(obj);
        }
        var len = keys.length;
        var add = "";
        for(var j = 1; j < level; j++)
        {
            // I would normally do {add = add.substr(0, level)} of a precreated multi-tab [add] string here, but Sublime keeps replacing with spaces, even with the ["translate_tabs_to_spaces": false] setting!!! (angry)
            add += "\t";
        }
    
        for (var i = 0; i < len; i++) 
        {
            prop = obj[keys[i]];
            if(!prop)
            {
                // Don't show / waste of space in console window...
                //console.log(add + level + ": UNDEFINED [" + keys[i] + "]");
            }
            else
            {
                typer = typeof(prop);
                if(typer == "function")
                {
                    // Don't bother showing fundtion code...
                    console.log(add + level + ": [" + keys[i] + "] = {" + typer + "}");
                }
                else
                if(typer == "object")
                {
                    console.log(add + level + ": [" + keys[i] + "] = {" + typer + "}");
                    if(nextLevel <= deep)
                    {
                        // drop the key search mechanism if first level item has been found...
                        this.reportObject(prop, "", nextLevel, deep); // Recurse into
                    }
                }
                else
                {
                    // Basic report
                    console.log(add + level + ": [" + keys[i] + "] = {" + typer + "} = " + prop + ".");
                }
            }
        }
        return ;
    };
    
    //console.log("END: AFutils");
    

    【讨论】:

      【解决方案5】:

      对于键/值的简单迭代,有时像 underscorejs 这样的库可以成为您的朋友。

      const _ = require('underscore');
      
      _.each(a, function (value, key) {
          // handle
      });
      

      仅供参考

      【讨论】:

      • 它对我有用。不知道underscorejs。我使用了 lodash 库中的这个函数。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-03-30
      • 2020-05-04
      • 1970-01-01
      • 1970-01-01
      • 2016-02-08
      • 1970-01-01
      • 2020-06-02
      相关资源
      最近更新 更多