How does the _.invoke method work in Lodash?

10,319

Solution 1

var result = _.invoke(items, fn, extraArgs)

Is equivalent to

var result = [];
for (var i=0; i<items.length; i++) {
  result.push( fn.apply(items[i], extraArgs) );
}

So if you want the same result as your map, it would be

_.invoke(items, function() {
  return _.omit(this, 'id');
})

The only difference is that item is not a parameter of the function, instead you need to use this as the function is applied to the item.

Solution 2

Make sure to note which version of lodash you are using.

v4.11.1 uses _.invokeMap when operating over a collection:

_.invokeMap([1,2,3], function () {
    console.log(this)
})

Solution 3

invoke calls the function as an instance method.

For example,

[
(new Date()).toString(),
(new Date()).toString(),
(new Date()).toString()
]

can be rewritten as:

_.invoke([new Date(), new Date(), new Date()], 'toString')

It is roughly analogous to map, where map is passed a function, but invoke is passed a method of the instances.

If you really want to make invoke work for you here, then I guess you could do it like this:

var items = [{id:1, name:'foo'}, 
             {id:2, name:'bar'}, 
             {id:3, name:'baz'}, 
             {id:4, name:'qux'}];
_.invoke(items, function() { return _.omit(this, 'id') });
// => [Object {name="foo"}, Object {name="bar"}, Object {name="baz"}, Object {name="qux"}]

but you shouldn't do that. Just use map.

Solution 4

As Joe Frambach suggested, map() is better suited for this.

var collection = [
    { id:1, name:'foo' },
    { id:2, name:'bar' },
    { id:3, name:'baz' },
    { id:4, name:'qux' }
];

_.map(collection, _.ary(_.partialRight(_.omit, 'id'), 1));
// → 
// [
//   { name: 'foo' },
//   { name: 'bar' },
//   { name: 'baz' },
//   { name: 'qux' }
// ]
Share:
10,319
Pete
Author by

Pete

Updated on July 23, 2022

Comments

  • Pete
    Pete almost 2 years

    Background

    From the documentation about the invoke method, I read:

    Invokes the method named by methodName on each element in collection, returning an array of the results of each invoked method

    Thus, I assumed that the following code would be synonymous, but this is not the case:

    _.map(items, function(item) {
        return _.omit(item, 'fieldName');
    })
    
    _.invoke(items, _.omit, 'fieldName');
    

    In this case, the invoke method produces an array of strings, while the map method returns an array of items with fieldName removed from each item.

    Questions

    • How can one use the invoke method to achieve the same result as the map function?
    • Why did invoke return the array of strings in this particular situation?

    var items = [{id:1, name:'foo'}, 
                 {id:2, name:'bar'}, 
                 {id:3, name:'baz'}, 
                 {id:4, name:'qux'}];
    
    console.log(
        _.invoke(items, _.omit, 'id')
    );
    
    console.log(
        _.map(items, function(item) {
            return _.omit(item, 'id');
        })
    );
    <script src="https://getfirebug.com/firebug-lite-debug.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.3.1/lodash.min.js"></script>