views:

207

answers:

3

What is apply invocation pattern in Javascript in reference to function invocation patterns and how can I use it? What are the benefits of using this invocation pattern.

+9  A: 

The use of apply is related to the function context (the this keyword) and argument passing.

First, I think you should know in which cases the this keyword is implicitly set:

1- When a function is called as a method (the function is invoked as member of an object):

obj.method(); // 'this' inside method will refer to obj

2- A normal function call:

myFunction(); // 'this' inside the function will refer to the Global object
// or 
(function () {})();

3- When the new operator is used:

var obj = new MyObj(); // this will refer to a newly created object.

Here is when apply and call come, those methods let you set explicitly the context when you invoke a function, eg.:

function test(a) {
  alert(this + a);
}

test.call('Hello', ' world!');

In the above code, when the test function is called setting the this keyword to a String ('Hello'), and passing the a argument (' world.').

Both, call and apply change the context of the executing function (the this keyword) inside the called function, but the difference between them is that with apply, you can send an Array or an Array-like object as the arguments of the function to be executed, which is extremely useful, for example:

function sum() {
  var result = 0;
  for (var i = 0; i < arguments.length; i++) {
    result += arguments[i];
  }
  return result;
}

var args = [1,2,3];
sum.apply(null, args); // will return 6

That can avoid some very hacky, bad (and common) eval calls like:

eval('sum(' + args.join() +')');

Another example, the Math.max and Math.min methods, those methods can receive an arbitrary number of arguments like:

var max = Math.max(2,4,6,8); // 8

But what if you have an Array of numbers?

var numbers = [2,4,6,8];
numbers.push(10);
var max = Math.max.apply(null, numbers); // 10

Also note that when null or undefined is used as the this argument with call or apply, the this object will refer to the Global object (similar to the case #2, normal function invocation).

For the Math.max example, the context is not really relevant, since they are just like "static" methods, the this keyword is not used internally...

CMS
+1 Very nice! ----
Pekka
Ah I think I get it now. The whole point that I missed was "the value of this is provided as the first parameters". Now it makes sense why we would like to differentiate apply method as a separate kind of invocation.So what is the diff. between call and apply keywords then?
Priyank
A: 

I'm not aware of any design patterns named The Apply Pattern so I don't really think this is at all related to design patterns. However, there is an apply method of function objects in javascript (along with the corresponding call method) so I'll be explaining those.

The apply and call methods basically allow an object to "steal" a method from another object. You see, in javascript, methods are bound very-very late: at invocation time. Only when a method is called is the value of 'this' resolved. In a normal method call:

some_object.do_something();

the 'this' keyword in do_something refers to some_object. Apply and call lets you re-assign 'this'. For example:

some_object.do_something.apply(another_object);

the 'this' keyword in do_something now refers to another_object. So you're calling the do_something method belonging to some_object on another_object.

Now, this is interesting and all but why would anyone want to do this? Here's a concrete example of why this is useful:

// say you want to get some DIVs in the document, you can get all of them with:
var some_divs = document.getElementsByTagName('DIV');

// say you want the third to fifth DIV in the document, some_divs looks like an
// array so you might think you can slice it, but it's not. It's a collection
// of elements that fakes being an array and doesn't implement the slice method.

// No worries, we can steal the slice method from an array 
// and apply it to some_divs:
var wanted_divs = [].slice.apply(some_divs,[2,5]);

// Alternatively:
var wanted_divs = [].slice.call(some_divs,2,5);

There is another use case for apply which is a result of the difference between how apply and call works. If you have all your arguments in an array and the function expects individual arguments you can use apply to pass the array and have the function see the content of the array as individual arguments:

function some_function (first,second) {
    alert(first+second);
}
var argument_array = ['hello','world'];
some_function.apply(null, argument_array);
slebetman
+1  A: 

You can also use call/apply for inheritance.

function Client (id) {
  this.id = id;
  this.name = "Client" + id;
}

Client.prototype = {
    constructor: Client

  , toString: function () {
      return this.name;
    }
};

function WebClient (id) {
  Client.call (this, id);
}

WebClient.prototype = new Client ();

WebClient.prototype.constructor = WebClient;

WebClient.prototype.ping = function () {
  // do stuff
};

Notice Client.call (this, id); This executes Client using the this instance that a new WebClient would create. Thus when

  this.id = id;
  this.name = "Client" + id;

are executed inside Client the WebClient instance is getting assigned those properties.

trinithis