Ітерація над об’єктними ключами в node.js


139

Оскільки у 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.



2
Що над головою? Скільки у вас клавіш і ітераторів? Якщо їхнього продукту менше 1 мільйона, просто ігноруйте цю «неефективність».
c69

@jcolebrand φ: Схоже, createNodeIteratorце для елементів DOM, я навіть не маю DOM;) @ c69: я зберігаю всі дані в keysоб'єкті, і valueвін просто встановлений 1(приблизно 20 Мб в 700k ключів), дійсно, для зараз я просто ігнорую цю «накладну», але я вважаю за краще краще рішення :)
stewe

Я бачив це як клас, з яким можна було
заплутатися

Відповіді:


246

Те, що ви хочете, - лінива ітерація над об'єктом або масивом. Це неможливо в ES5 (таким чином, це неможливо в node.js). Ми отримаємо це врешті-решт.

Єдине рішення - пошук модуля вузла, який розширює V8 для реалізації ітераторів (і, можливо, генераторів). Я не зміг знайти жодної реалізації. Ви можете подивитися вихідний код spidermonkey і спробувати записати його на C ++ як розширення V8.

Ви можете спробувати наступне, однак це також завантажить усі клавіші в пам'ять

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

Однак оскільки Object.keysце власний метод, він може забезпечити кращу оптимізацію.

Орієнтир

Як ви бачите, 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

@stewe додав (а)async.forEach
Raynos

Дякую за роз’яснення! Я, мабуть, спробую розширення c ++.
stewe

2
@stewe якщо вам вдасться його написати, опублікуйте його на github та залиште посилання на нього у відповіді тут або коментарі о /
Raynos

@stewe про те розширення на C ++, ти його написав?
Райнос

22

Також пам’ятайте, що ви можете передавати другий аргумент .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);

5
приємне доповнення до теми, але ... чому на землі показують ключ об'єкта, що передається, як щось, що називається "елемент", а перечислювач для масиву ключів називається "ключ" ?! Можна запропонувати вам оновити зразок коду для використанняObject.keys(myObject).forEach(function(key, index, arrayOfKeys) {
Енді Лоренц

4

Для простої ітерації ключа / значень іноді бібліотеки, такі як підкреслювачі, можуть стати вашим другом.

const _ = require('underscore');

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

лише для довідки


Це працювало для мене. Не знаю про це underscorejs. Я використовував цю функцію з lodashбібліотеки.
Неералі Ачарія

3

Я новачок у 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");

0

коригуйте його код:

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);
    });
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.