简体   繁体   中英

Can a lazy iterator for the keys of an object be implemented in ES5 JavaScript without loading all keys of the object into memory at once?

I want to write a ES5 JavaScript function (ie without generators or Symbol.iterator ) that accomplishes what the following generator function does in ES6:

function *keys(o) {
  for (let key in o)
    yield key
}

I want to return a lazy iterator without loading all of the keys into memory at once , so Object.keys is off the table since it returns an array of the keys. However, I can't seem to figure out how to do it.

I was getting desperate so I started looking into how generators are transpiled into versions of JavaScript which do not support them. If you input the generator function above into Facebook's Regenerator , you get the following output:

var _marked =
/*#__PURE__*/
regeneratorRuntime.mark(keys);

function keys(o) {
  var key;
  return regeneratorRuntime.wrap(function keys$(_context) {
    while (1) {
      switch (_context.prev = _context.next) {
        case 0:
          _context.t0 = regeneratorRuntime.keys(o);

        case 1:
          if ((_context.t1 = _context.t0()).done) {
            _context.next = 7;
            break;
          }

          key = _context.t1.value;
          _context.next = 5;
          return key;

        case 5:
          _context.next = 1;
          break;

        case 7:
        case "end":
          return _context.stop();
      }
    }
  }, _marked, this);
}

After reading through this output I thought that the implementation of regeneratorRuntime.keys might hold the answer, but it appears that this function loads all of the keys into memory at once:

exports.keys = function(object) {
  var keys = [];
  for (var key in object) {
    keys.push(key);
  }
  keys.reverse();

  // Rather than returning an object with a next method, we keep
  // things simple and return the next function itself.
  return function next() {
    while (keys.length) {
      var key = keys.pop();
      if (key in object) {
        next.value = key;
        next.done = false;
        return next;
      }
    }

    // To avoid creating an additional object, we just hang the .value
    // and .done properties off the next function object itself. This
    // also ensures that the minifier will not anonymize the function.
    next.done = true;
    return next;
  };
};

Any ideas?

No, there is no way to create a lazy property iterator. ES6 had Reflect.enumerate , and generator functions allow you to write that keys helper, but in ES5 no such facility exists - given that ES5 did not have any iterator concept, that's not surprising.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM