Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lodash forOwn and forOwnRight iteration order

In lodash you can find the following functions:

_.forOwn _.forOwnRight

Example for forOwn function iterates properties in a-z order, but says:

iteration order is not guaranteed

While forOwnRight claims to be iterating in opposite (z-a) order.

This does not make much sense to me, so there are 2 questions

  1. Why does forOwnRight even exist if there is no guarantee on iteration order?
  2. Why can't the order be guaranteed?
like image 463
Anri Avatar asked Feb 11 '23 15:02

Anri


2 Answers

  1. The order is not guaranteed but is consistent. It means that _.forOwnRight is guaranteed to provide the result reversed from _.forOwn

  2. It's as per specification: it does not state how object's properties must be ordered so it's up to JS engine how to handle it (and they do that differently for performance reasons).

A note: the order depends not only on the particular ES implementation, but also on runtime, since modern JS VMs do a lot of heuristics in runtime.

For the ones curious about optimizations here is a good link (it seriously does not fit to cover in this Q/A):

  • https://developers.google.com/v8/design
like image 98
zerkms Avatar answered Feb 13 '23 05:02

zerkms


Looking at the source we can see that:

function baseForOwn(object, iteratee) {
    return baseFor(object, iteratee, keys);
}

function baseForOwnRight(object, iteratee) {
    return baseForRight(object, iteratee, keys);
}

function baseFor(object, iteratee, keysFunc) {
    var index = -1,
        iterable = toObject(object),
        props = keysFunc(object),
        length = props.length;
    while (++index < length) {
        var key = props[index];
        if (iteratee(iterable[key], key, iterable) === false) {
            break;
        }
    }
    return object;
}

function baseForRight(object, iteratee, keysFunc) {
    var iterable = toObject(object),
        props = keysFunc(object),
        length = props.length;
    while (length--) {
        var key = props[length];
        if (iteratee(iterable[key], key, iterable) === false) {
            break;
        }
    }
    return object;
}

Both of the functions internally rely on keysFunc, which returns the keys of the passed object. Since the order of an object's keys is not strictly defined the order cannot be known beforehand, however both of the methods internally use the same method, so the reversed order is guaranteed to be an exact reversal.

like image 27
Etheryte Avatar answered Feb 13 '23 03:02

Etheryte