dtao / lazy.js

Like Underscore, but lazier
http://danieltao.com/lazy.js/
MIT License
6.01k stars 267 forks source link

`get` does not deep pick. Syntactically pleasing workaround? #167

Open Redsandro opened 8 years ago

Redsandro commented 8 years ago

Allow me to speak in code:

var obj = {
    family: 'Fosters',
    person : {
        name : 'Hank',
        data : {
            id : 2,
            checked : false
        }
    }
};

var amend = {
    person : {
        data : {
            checked : true
        }
    }
};

var fam = Lazy(obj).assign(amend);

fam.get('family');
// 'Fosters'

fam.get('family.person.data.checked');
// undefined
// EXPECTED: true

Can I do this in a syntactically pleasant way?

Perhaps get should be extended so we can do something like: fam.get(['family', 'person', 'data', 'checked'])

Redsandro commented 8 years ago

Of course I can do fam.get('family').person.data.checked, but I want to prevent generating objects every time I need to reference a variable. Also it would be nice if lazy.js would handle " Cannot read property 'checked' of undefined" cases and just return undefined.

Redsandro commented 8 years ago

I should use merge in stead of assign. But the question remains.

get(key) could backwards traverse the mergedSequence.others array up to the mergedSequence.parent object until key is found.

Redsandro commented 8 years ago

Perhaps get should be extended so we can do something like: fam.get(['family', 'person', 'data', 'checked'])

@dtao I think the relavant code is at jazy.js:3576:

  ObjectLikeSequence.prototype.get = function get(key) {
    var pair = this.pairs().find(function(pair) {
      return pair[0] === key;
    });

    return pair ? pair[1] : undefined;
  };

Now this doesn't work but I feel like it can be translated to lazy.js magic, and we'll be able to deep get values if we use an array as key:

  ObjectLikeSequence.prototype.get = function get(keys) {
    var key, ret;

    if (typeof keys == 'array') {
      if (!keys.length)
        return undefined;
      key = keys.shift();
    }
    else
      key = keys;

    var pair = this.pairs().find(function(pair) {
      return pair[0] === key;
    });

    ret = pair ? pair[1] : undefined;

    if (keys.length) {
      if (typeof ret == 'object')
        return ret.get(keys);
      else
        return undefined;
    }

    return ret;
  };
nicemaker commented 8 years ago

If that gets implemented I was just wondering if it wouldn't be nicer to have the syntax like

fam.get( 'family.person.data.checked' )
Redsandro commented 8 years ago

Perhaps both, string with dots (sugar) and array, so people nitpicky about speed (like me) can skip the detection and splitting.

Nepoxx commented 8 years ago

@nicemaker That's be nice considering that is how Lodash does it (so newcomers (like me!) would feel right at home), however I second @Redsandro that an array would be faster than parsing/splitting a string.

I was under the impression that the following would work, but it doesn't and I'm not sure why:

fam.pick('family').pick('person').pick('data').pick('checked')
dtao commented 6 years ago

I'm on the fence on this one. On the one hand, I'm not sure deep-picking really falls under the purview of this library. Lazy.js is about dealing with sequences; I never envisioned it as a do-everything utility belt. On the other hand, I have historically compared it directly to Underscore and Lodash, which describe themselves as utility libraries. So maybe it's only fair to expect this.

I'll have a think on it.