3

What I'm trying to say with the title is:

Is there a difference in:

argument = [arg1, arg2, arg3];
Foo.bar.apply(Foo, argument);

compared to:

Foo.bar(arg1, arg2, arg3);

Except the obvious (argument vs. non argument)?

What is the reason to use the two following different "calling" methods for the same method (bar)? I have understand that apply has to do with the calling object, but is there a difference in this case?

What is the difference between call and apply? gives a lot of info regarding apply, but I haven't found a good answer to why to pass "myself".

The longer story:

/* This is the bar method in CFoo class */
CFoo.prototype.bar = function(a,b,c) {
  /* 
   * Magic things happen here,
   * and also...
   */
  if (a == "SomthingSpecial") {
    this.bar(a,b);
  }
}

Most of the place where bar is called it is via an global instance of CFoo.

/* In the begining... */
Foo = new CFoo();

/* Some other place */
Foo.bar("Test", 3, function(v) {
    /* Some stuff */
});

/* And another place */
arr = ["Test2", 4, function(v) {
    /* Other stuff */
}];
Foo.bar.apply(Foo, arr);

Edit: Explained the title a bit more. Answered in @nils answer comment.

Community
  • 1
  • 1
Mats
  • 33
  • 6

2 Answers2

3

The "and another place" code, where .apply() is used, apparently wants to use an existing array as the argument list for an invocation of the function. The only (easy) way to do that in JavaScript is with .apply.

In other words, the code has an array:

arr = ["Test2", 4, function(v) {
    /* Other stuff */
}];

and wants to get the effect of

Foo.bar("Test2", 4, function(v) { ... });

That is, it wants to call Foo.bar() with the array elements as arguments. To do that, it can use .apply(), but in order to make sure that this is a reference to object Foo it passes Foo as the first parameter.

So there are two requirements that come together:

  1. The function Foo.bar() is designed to work with a correctly-set value for this, so it must be invoked either as Foo.bar() or in some way such that Foo is used as the value of this;
  2. For some reason, a list of arguments to be passed in to Foo.bar() has been generated or computed or whatever, and that list is in an array.
Pointy
  • 405,095
  • 59
  • 585
  • 614
  • ohhhhh...I see. After reading the question. I wondered why? This is a nice technique – Abdullah Rasheed Nov 18 '15 at 14:15
  • Yes true. But the code is more accurate than it seems. The thing is that the array is created right before the apply, so it makes no sense to me. If the array was a result of something i had bought it right away. – Mats Nov 18 '15 at 14:21
  • 1
    @Mats regardless of where/how the array is created, if it is necessary to use an array as a parameter list then `.apply()` (or the new `...` operator as described in nils' answer) must be used. – Pointy Nov 18 '15 at 14:24
2

.apply() does two things:

  1. The first argument changes the context (this) of the function call.
  2. The second argument is an array that is applied to your function. So each value in your array will be an argument value when bar is called. That would lead to a=arr[0], b=arr[1], c=arr[2]

To demonstrate why you need to pass in Foo as your context, let's look at an example. If you were to call the following, it would fail, because this would equal null:

Foo.bar.apply(null, arr); // null instead of Foo

// in the function call...
if (a == "SomthingSpecial") {
  this.bar(a,b); // this == null here
}

Alternative Approach (EcmaScript 2015)

If you can work with EcmaScript 2015 and want to avoid having to pass the context, you could use the spread operator instead:

Foo.bar(...arr); // Spreading the array with the spread operator
nils
  • 25,734
  • 5
  • 70
  • 79
  • I got that to, but is there a difference in Foo.bar(a,b,c); and Foo.bar.apply(Foo, arr); Where arr = [a,b,c];? – Mats Nov 18 '15 at 14:23
  • Not directly. It really depends on the data you have beforehand. If you have an array (`var arr = [a,b,c];`), use `apply` or `...`. If you have singular variables (`var a = 'a';`), call `bar` directly. (as Pointy pointed out in his comments below) – nils Nov 18 '15 at 14:33
  • I select your answer as the best for my question since the question boiled down to if there is a difference in the calling methods. – Mats Nov 19 '15 at 07:32