在 node.js 中迭代对象键

因为 Javascript 1.7有一个 迭代器对象,它允许:

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中,会产生大量开销。

324271 次浏览

您需要的是对对象或数组进行延迟迭代。这在 ES5中是不可能的(因此在 node.js 中是不可能的)。我们最终会拿到的。

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

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

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

然而,由于 Object.keys是一种本地方法,它可能允许更好的优化。

基准

正如您所看到的 Object.key 的速度明显更快,而实际的内存存储是否更加优化则是另一回事。

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);
});

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

// 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.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);
});

我是 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");

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

const _ = require('underscore');


_.each(a, function (value, key) {
// handle
});

仅供参考

您可以很容易地编写自己的迭代器:

let iterateObject = function*(obj) {
for (let k in obj) yield [ k, obj[k] ];
};

现在我们可以做的是:

let myObj = {
a: 1,
b: 2,
c: 3
};
for (let [ k, v ] of iterateObject(myObj)) {
console.log({ k, v });
}


// Produces:
// >> { k: 'a', v: 1 }
// >> { k: 'b', v: 2 }
// >> { k: 'c', v: 3 }

注意,这种方法成功地避免了在内存中存储所有 Object 值!

请注意,从节点版本 4.0.0开始就支持 function*(){},并且从 6.0.0开始就支持解构(如使用生成器的 for循环所示) !