Node.js dosyasındaki nesne anahtarları üzerinden yineleme


139

Javascript 1.7'den beri buna izin veren bir Iterator nesnesi var :

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'de böyle bir şey var mı?

Şu anda kullanıyorum:

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

ancak bu, tüm nesne anahtarlarını depolayarak çok fazla yük oluşturur k.



2
Ne yükü? Kaç anahtarınız ve yineleyiciniz var? Ürünleri 1 milyondan azsa, bu 'verimsizliği' göz ardı edin.
c69

@jcolebrand φ: Görünüşe createNodeIteratorgöre DOM elemanları için, hatta bir DOM bile yok;) @ c69: i keysnesnenin tüm verilerini depolar ve valuesadece 1(700k anahtarlarda yaklaşık 20MB) olarak ayarlanır. şimdi sadece bu 'havai' görmezden, ama daha iyi bir çözüm tercih ederim :)
stewe

Ben ;-)
jcolebrand

Yanıtlar:


246

İstediğiniz şey bir nesne veya dizi üzerinde tembel yineleme. Bu ES5'te mümkün değildir (bu nedenle node.js'de mümkün değildir). Bunu eninde sonunda alacağız.

Tek çözüm, V8'i yineleyicileri (ve muhtemelen jeneratörleri) uygulamak için genişleten bir düğüm modülü bulmaktır. Herhangi bir uygulama bulamadım. Spidermonkey kaynak koduna bakabilir ve C ++ ile V8 uzantısı olarak yazmayı deneyebilirsiniz.

Aşağıdakileri deneyebilirsiniz, ancak tüm anahtarları belleğe yükler

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

Ancak Object.keys, yerel bir yöntem olduğundan daha iyi optimizasyona izin verebilir.

Karşılaştırma

Gördüğünüz gibi Object.keys çok daha hızlı. Gerçek bellek depolama alanının daha optimum olup olmadığı farklı bir konudur.

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

! Teşekkürler, bu benim yineleyici (kod güncellenir) biraz :) ama ne yazık ki hafıza sorunu kalıntıları geliştirir :( Ve kullanamaz forEachher yineleme adımı bir zaman uyumsuz çağırılabilir gerektiğinden setTimeout.
Stewe

@stewe anasync.forEach
Raynos

Açıklama için teşekkürler! Muhtemelen c ++ eklenti yaklaşımını deneyeceğim.
stewe

2
@stewe yazmayı başarırsanız, github'da yayınlar ve burada bir cevapta veya bir yorumda bir bağlantı bırakırsanız o /
Raynos

@stewe bu C ++ uzantısı hakkında yazar mıydınız?
Raynos

22

Ayrıca .forEach(), thisanahtar kelime olarak kullanılacak nesneyi belirten işleve ikinci bir argüman iletebileceğinizi unutmayın .

// 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
iş parçacığına güzel bir ek, ama ... neden yeryüzünde "element" denilen bir şey olarak geçirilen nesnenin anahtarını ve "key" adlı anahtar dizisi için numaralandırıcı gösterir?! Kullanmak için kod örneğinizi güncellemenizi önerebilir miyimObject.keys(myObject).forEach(function(key, index, arrayOfKeys) {
Andy Lorenz

4

Anahtar / değerlerin basit bir şekilde yinelenmesi için, bazen underscorejs gibi kütüphaneler arkadaşınız olabilir.

const _ = require('underscore');

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

Sadece referans için


Benim için çalıştı. Bilmiyorum underscorejs. Bu işlevi lodashkütüphaneden kullandım.
Neerali Acharya

3

Düğüm.js'de yeniyim (yaklaşık 2 hafta), ancak bir nesnenin içeriğini konsola yinelemeli olarak bildiren bir modül oluşturdum. Hepsini listeleyecek veya belirli bir öğeyi arayacak ve gerekirse belirli bir derinliğe göre ayrıntıya inecektir.

Belki de bunu ihtiyaçlarınıza göre özelleştirebilirsiniz. Basit Tutun! Neden karmaşık?

'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

kodunu ayarlayın:

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);
    });
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.