Search code examples
javascriptarraysobjectmethodsunderscore.js

Having a problem with rewriting invoke function inspired by underscore library


I'm a beginner and trying to rewrite an underscore function _.invoke. I'm trying to make the function so it returns an array with the results of calling the method on each value in the collection.

_.invoke = function(collection, methodName) {
  var result = [];
  if (Array.isArray(collection)) {
    for (let i = 0; i < collection.length; i++) {
      methodName.call(collection[i])
      var value = collection[i][methodName]
      result.push(value)
    }
  }
  return result
}

I think my problem lays in this line:

methodName.call(collection[i]) - would like to invoke method on an object collection[i] but I would like to pass some arguments should they be included in the unit test.

I've tried so far utilizing the test : typeof(methodName) === "function" and writing a function that would test whether the method is a function.


Solution

  • You mean something like this?

    const myArr = [
      { cons:function(args) { return args } },
      { cons:function(args) { return args["bla"] } },
    ]
    
    const _ = {};
    _.invoke = (collection, methodName, ...args) => !Array.isArray(collection) ? [] : collection
    .filter(item => typeof item[methodName] === 'function')
    .map(item => item[methodName].apply(item, args));
    
    const res = _.invoke(myArr,"cons",{"bla":"hello"})
    console.log(res)

    Here is a more performant version if you need speed over a lot of entries

    const myArr = [
      { cons: function(args) { return args; } },
      { cons: function(args) { return args["bla"]; } },
    ];
    
    const _ = {};
    _.invoke = (collection, methodName, ...args) => {
      const result = [];
      if (!Array.isArray(collection)) return result;
    
      for (let i = 0, len = collection.length; i < len; i++) {
        const item = collection[i];
        const method = item[methodName];
    
        if (typeof method === 'function') {
          result.push(method.apply(item, args));
        }
      }
    
      return result;
    };
    
    const res = _.invoke(myArr, "cons", {
      "bla": "hello"
    });
    console.log(res);