Reputation: 6323
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
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
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