skeggse
skeggse

Reputation: 6323

Javascript Function: Applying Apply

I got stumped by this weirdness.

Let's say I have this array:

var array = [{
  something: 'special'
}, 'and', 'a', 'bunch', 'of', 'parameters'];

Could I apply the apply method of a function to invoke the function with the this object being {something: 'special'} and the parameters being the rest of array?

In other words, could I do this

var tester = function() {
  console.log('this,', this);
  console.log('args,', arguments);
};
tester.apply.apply(tester, array);

And expect the output to be the following?

> this, {"something": "special"}
> args, {"0": "and", "1": "a", "2": "bunch", "3": "of", "4": "parameters"}

I tried it.

TypeError: Function.prototype.apply: Arguments list has wrong type

But why? It seems like this should work.

Upvotes: 6

Views: 970

Answers (2)

basilikum
basilikum

Reputation: 10528

The apply method takes one argument for the this context and one argument for the arguments, that you want to apply. The second argument must be an array.

tester.apply.apply(tester, array);

Due to the second apply method, the first will be called like this:

tester.apply({something: 'special'}, 'and', 'a', 'bunch', 'of', 'parameters');

And since 'and' is not an array, you get the TypeError that you described. You can easily fix this by using the call method:

tester.call.apply(tester, array);

call will take individual arguments instead of an array, which will result in the desired outcome.

Upvotes: 0

Bergi
Bergi

Reputation: 664385

But why?

Let's reduce your calls step-by-step:

tester.apply.apply(tester, array) // resolves to
(Function.prototype.apply).apply(tester, array) // does a
tester.apply({something: 'special'}, 'and', 'a', 'bunch', 'of', 'parameters');

Here you can see what's going wrong. Correct would be

var array = [
    {something: 'special'},
    ['and', 'a', 'bunch', 'of', 'parameters']
];

then the apply.apply(tester, array) would become

tester.apply({something: 'special'}, ['and', 'a', 'bunch', 'of', 'parameters']);

which does a

tester.call({something: 'special'}, 'and', 'a', 'bunch', 'of', 'parameters');

So with your original array you'd need to use

(Function.prototype.call).apply(tester, array)

Upvotes: 11

Related Questions