The Flavors of JavaScript Function Invocation

The Flavors of JavaScript Function Invocation

For those who may not be in the know, Functions in JavaScript are really very cool. They’re first class objects. What does that mean? It means that  JavaScript functions can have properties and methods just like other objects. Yes, you read that correctly, JavaScript functions can have their own properties and methods. In fact, Functions in JavaScript have all the same abilities as other JavaScript objects. What abilities are those? I’m glad you asked.

  • They can be assigned to variables
  • They can be assigned to properties of other objects
  • They can be passed as arguments
  • They can be created via literals

In additional to all of this cool stuff, they can do something that regular JavaScript objects cant’; they can be invoked! This invocation at first glance may appear to be a trivial thing but there’s much more nuance here than meets the eye.  You see, dear reader, that a JavaScript function can be invoked in four distinct ways. They are:

  1. As a function
  2. As a method
  3. As a constructor
  4. using either the call() of apply() methods that all functions have access to

One thing to keep in mind as you review these invocation methods is “this”. If you’ve been working with JavaScript for any amount of time you’ve no doubt run across the concept of “this”. “this” refers to the current context and can trip people up sometimes when they aren’t aware of what’s going on under the JavaScript covers.

Lets take a look at each of these invocation methods.

Function invocation as a function

When we say we invoking a function as a function, what we mean is that the function:

  1. Does not have a relationship with any object
  2. Is not a constructor
  3. Is not being called via call() or apply()

Its pretty simple really and it looks like this:

function printName(){
    console.log('hi there');
}
printName();

When a function is invoked in this manner, its context or “this” is the global window object. Not usually something that we want but no doubt something that all of us have done in our JavaScript travels.

Function invocation as a method

When we invoke a function as a method, the context or “this” is that of the object to which it belongs. So if you reference “this” from within the method, it will point to the object to which the function belongs. Here’s an example:

//here is a fuction
function printMe(){console.log('hi from print. my owner is ' + this);}

//our object with a method that points to the function
var printer = {
    p: printMe
};

//lets test them out
printMe();
printer.p();

and there is the output in Chrome developer tools:

JSFunctions_this

So, what’s happening here? First we define a function called printMe(). It is attached to the global window object. I then define an object with a property p that points to the printMe() function. The interesting part is when I invoke these guys and print out their context. As you can see in the output, the first call to printMe() has the [object Window] set at its owner/context while the second call to it displays [object Object]. This is the object on which the property is attached as its owner/context.

Now, let’s invoke the function as a constructor and see what we get. Here’s the code:

function Printer(){
    this.printMe = function(){
        console.log('hi from printMe method made via constructor');
        return this;
    };
}

var p = new Printer();
console.log(p.printMe() instanceof Printer);

and the results:

JSFunctions_this_constructor

What does this show us. First you can see that we have named our Printer() function with a capital P to denote that this is a constructor. That’s a convention that is worth following. Beyond that, you can see that inside the constructor, we attach the printMe function to the context “this”. We’re initializing our object much the same way we would in an object oriented language. After that we create a new instance of our Printer being sure to use the “new” keyword. That’s very important. Don’t forget to use new. If you were to omit new from the statement, the printMe function would be added to the global window object. Probably not what you’re looking for. Finally, we test to affirm that what we get back from our call to p.printMe() is an instance of a Printer and indeed it is.

You can see in each of these methods above that the context changed based solely on how we invoke the function. What if we wanted to tell the function what its context should be? That sounds like it might be a useful feature. The good news is that we can do just that using the call() and apply() methods. Lets look at that next.

Function invocation via call() and apply()

Being able to specify the context for function invocation can come in handy. Lets look at some code that does just that.

function add(){
    var result = 0;
    for (var i = 0; i < arguments.length; i++) {
      result += arguments[i];
    }
    this.result = result;
}
var myObj1 = {};
var myObj2 = {};

add.apply(myObj1, [2, 3, 4]);
add.call(myObj2, 3, 4, 5);

console.log(myObj1.result);

console.log(myObj2.result);

Here we define a function named add() that loops over all the arguments passed to it and adds them it. Is then references its context via this and attaches a new results property to the object. Very cool stuff.

The difference between call() and apply() are the parameters that each takes. When using apply(), the first parameter is the object that you want to be the context and the second parameter is an array containing the values. call() works in much the same way also using the first parameter to set context followed by a comma separated list of values rather than an array. The result as seen in the debug tools is as follows:

Add

The first call using apply adds 2+3+4 giving us a sum of 9.

The second call using call() adds 3+4+5 giving us 12.

I hope this was useful and you picked up a couple of things along the way. Remember, there are 4 ways to invoke functions in JavaScript: as a function, as a method, as a constructor and via call() and apply().  Each of these has its own purpose and will serve you well when used appropriately. When working with your functions always keep context in mind and know what context you are working with.

Until next time….thanks for visiting.

Leave a Reply

Your email address will not be published. Required fields are marked *

Get Adobe Flash player