Search code examples
javascriptnode.jsfunctionprototypeecmascript-2016

JavaScript - Apply function call to object with another prototype


The task (actually the problem) I'm facing is the following. I have an array (let’s call it arr). The first element of the array is a function and the rest are arguments. For example:

arr = [(a, b) => a + b, 5, 7];

So, I need to call function (a, b) => a + b with arguments 5 and 7. However, I don't want to use arr[0](...arr.slice(1)), instead I want to do it using Function.prototype.apply and Function.prototype.call (I can also use Function.prototype.bind if needed). So basically, I am allowed to access arr only once and no other variables may be used. Also, I'm not allowed to modify arr or it's properties, or to store any other data somewhere (like as property of some global object, etc). Is that even possible?

My attempt

I tried to figure it out, and this is what I came up with (it doesn't work):

Function.prototype.apply.call(this, ...arr);

However, it throws an error saying:

Uncaught TypeError: Function.prototype.apply was called on #Global, which is an object and not a function

Question

What is the correct way to do this?


Solution

  • You can use destructuring to get the elements of arr array as variables, then call the function at index 0 with elements at indexes 1-N

    let arr = [(a, b) => a + b, 5, 7];
    let [fn, a, b] = arr;
    console.log(fn(a, b));

    For any number of elements at indexes 1-N you can use rest element

    let arr = [(a, b) => a + b, 5, 7];
    let [fn, ...rest] = arr;
    console.log(fn.apply(null, rest));

    Alternatively, using Function, template literal to convert array to string, .replace() with RegExp /\s/g with .replace() to remove space characters, .match() with RegExp /(\(.*\)=>[^,]+(?=,))|[^,]{1}[^\1]+/g to capture arrow function, negate first comma of characters that are not arrow function and arrow function captured at first group, we can reference arr once and not create additional variables save for immediately invoked arrow function parameters

    let arr = [(a, b) => a + b, 5, 7];
    
    console.log(
      (([a, b]) => new Function(`return (${a})(${b.split(/,/)})`)())
      (`${arr}`.replace(/\s/g, "").match(/(\(.*\)=>[^,]+(?=,))|[^,]{1}[^\1]+/g))
    )