Iterieren Sie über Objektschlüssel in node.js


139

Seit Javascript 1.7 gibt es ein Iterator- Objekt, das Folgendes ermöglicht:

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

Gibt es so etwas in node.js?

Im Moment benutze ich:

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

Dies führt jedoch zu einem hohen Overhead, da alle Objektschlüssel gespeichert werden k.



2
Was für ein Aufwand? Wie viele Schlüssel und Iteratoren haben Sie? Wenn ihr Produkt weniger als 1 Million beträgt, ignorieren Sie einfach diese "Ineffizienz".
c69

@jcolebrand φ: Es scheint createNodeIteratorfür DOM-Elemente zu sein, ich habe nicht einmal ein DOM;) @ c69: Ich speichere alle Daten im keysObjekt und das valueist nur auf 1(ungefähr 20 MB in 700k Schlüsseln) eingestellt, in der Tat für Jetzt ignoriere ich nur diesen 'Overhead', aber ich würde eine bessere Lösung bevorzugen :)
Stewart

Ich sah es als eine Klasse, mit der man sich
anlegen sollte ;-)

Antworten:


246

Was Sie wollen, ist eine verzögerte Iteration über ein Objekt oder Array. Dies ist in ES5 nicht möglich (daher in node.js nicht möglich). Wir werden das irgendwann bekommen.

Die einzige Lösung besteht darin, ein Knotenmodul zu finden, das V8 erweitert, um Iteratoren (und wahrscheinlich Generatoren) zu implementieren. Ich konnte keine Implementierung finden. Sie können sich den Spidermonkey-Quellcode ansehen und versuchen, ihn in C ++ als V8-Erweiterung zu schreiben.

Sie können Folgendes versuchen, es werden jedoch auch alle Schlüssel in den Speicher geladen

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

Da es sich jedoch Object.keysum eine native Methode handelt, kann dies eine bessere Optimierung ermöglichen.

Benchmark

Wie Sie sehen können, ist Object.keys deutlich schneller. Ob der tatsächliche Speicher optimaler ist, ist eine andere Frage.

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

Danke!, Dies verbessert meinen Iterator ein wenig :) (hat den Code aktualisiert), aber leider bleibt das Speicherproblem bestehen :( Und ich kann nicht verwenden, forEachda jeder Iterationsschritt von einem setTimeout
asynchronen

@stewe fügte hinzuasync.forEach
Raynos

Danke für die Klarstellung! Ich werde wahrscheinlich den C ++ - Erweiterungsansatz ausprobieren.
Stewart

2
@stewe, wenn Sie es schaffen, es zu schreiben, veröffentlichen Sie es auf Github und hinterlassen Sie einen Link dazu in einer Antwort hier oder einem Kommentar o /
Raynos

@stewe über diese C ++ - Erweiterung, hast du sie verfasst?
Raynos

22

Denken Sie auch daran, dass Sie der .forEach()Funktion, die das als thisSchlüsselwort zu verwendende Objekt angibt, ein zweites Argument übergeben können .

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

5
nette Ergänzung zum Thread, aber ... warum um alles in der Welt wird der Schlüssel des übergebenen Objekts als "Element" und der Enumerator für das Schlüsselarray "Schlüssel" angezeigt ?! Kann ich vorschlagen, dass Sie Ihr Codebeispiel für die Verwendung aktualisierenObject.keys(myObject).forEach(function(key, index, arrayOfKeys) {
Andy Lorenz

4

Für eine einfache Iteration von Schlüsseln / Werten können manchmal Bibliotheken wie Unterstriche Ihr Freund sein.

const _ = require('underscore');

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

nur als Referenz


Es hat bei mir funktioniert. Ich weiß es nicht underscorejs. Ich habe diese Funktion aus der lodashBibliothek verwendet.
Neerali Acharya

3

Ich bin neu in node.js (ca. 2 Wochen), habe aber gerade ein Modul erstellt, das den Inhalt eines Objekts rekursiv an die Konsole meldet. Es werden alle aufgelistet oder nach einem bestimmten Element gesucht und bei Bedarf ein Drilldown um eine bestimmte Tiefe durchgeführt.

Vielleicht können Sie dies an Ihre Bedürfnisse anpassen. Halte es einfach! Warum komplizieren? ...

'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");

0

Passen Sie seinen Code an:

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);
    });
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.