unfollow
unfollow

Reputation: 225

Invoking a Method dynamically | Javascript

I've created a function called multiMap, which takes two arrays as parameters and maps them to key value pairs in an object. In some circumstances, the second array of values might be functions, which will become methods in my newly created object.

I want the method values to be invoked with their corresponding key passed in as a string argument. I'm trying this with the line obj[item1].call(item1); but I can't seem to invoke the function correctly this way. Appreciate any help.

let multiMap = (arr1, arr2) => {
  const obj = {};
  
  for(let item1 of arr1) {
    for(let i = 0; i < arr2.length; i++) {
      let item2 = arr2[i]
      obj[item1] = item2;
  		obj[item1].call(item1);
    }    
  }
  

  return obj;
}

function uppercaser(str) { return str.toUpperCase(); }
function capitalize(str) { return str[0].toUpperCase() + str.slice(1).toLowerCase(); }
function repeater(str) { return str + str; }

var items = ['catfood', 'glue', 'beer'];
var functions = [uppercaser, capitalize, repeater];
console.log(multiMap(items, functions)); // should log: { catfood: ['CATFOOD', 'Catfood', 'catfoodcatfood'], glue: ['GLUE', 'Glue', 'glueglue'], beer: ['BEER', 'Beer', 'beerbeer'] }

Upvotes: 0

Views: 33

Answers (1)

Mark
Mark

Reputation: 92440

You have a couple things going wrong here.

First call takes a this as it's first argument and the actual argument comes after. Since you're not using this in the functions, you can just pass null: item2.call(null, item1) .

Also, since you want an array of values, at some point you need to make that array. I would recommend after the first for:

let multiMap = (arr1, arr2) => {
    const obj = {};
    
    for(let item1 of arr1) {
       obj[item1] = []                            // make the array
      for(let i = 0; i < arr2.length; i++) {
        let item2 = arr2[i]
        obj[item1].push(item2.call(null, item1)); // now just push into the array
      }    
    }
    return obj;
}
  
function uppercaser(str) { return str.toUpperCase(); }
function capitalize(str) { return str[0].toUpperCase() + str.slice(1).toLowerCase(); }
function repeater(str) { return str + str; }

var items = ['catfood', 'glue', 'beer'];
var functions = [uppercaser, capitalize, repeater];
console.log(multiMap(items, functions)); 

Also since you're not using call's ability to set this, you can just call the functions directly:

 obj[item1].push(item2(item1)); 

Putting all these together with map you could simplify the function to:

let multiMap = (arr1, arr2) => {
    const obj = {}; 
    for(let item1 of arr1) {
        obj[item1] = arr2.map(fn => fn(item1))
    }
    return obj;
}

or even:

let multiMap = (arr1, arr2) => {
    return arr1.reduce((obj, item) => {
        obj[item] = arr2.map(fn => fn(item))
        return obj
    }, {}) 
}

Upvotes: 1

Related Questions