Javascript is based… Object-Based

I had an interview question asking me to explain what call(), apply() and bind() functions do, and what this means in Javascript. It was a good refresher of what kind of language Javascript is and the crazy things you can do with it. So I’m going to try to answer the question in great detail.

A good place to start is by understanding that Javascript is an Object-Based language which happens to NOT be an Object-Oriented Language. Naturally, when you are a newbie at programming you look at the names Java and Javascript and you are to believe they are related in some way. They are not at all. In fact, Javascript was named as such to ride off the popularity of Java. Not because they are similar.

In Javascript, everything that is not a primitive type is an Object. Therefore, even functions in Javascript are Objects. They are a special type of Object and you can test this in the browser’s console by opening the developer tools [F12].

So why is this important to know? Long story short, inheritance doesn’t work the same in Javascript as it does in traditional OOP languages such as Java or C#. The thing is, Javascript doesn’t have “classes”, only objects.

Since Javascript has no classes, you could define a random object like this:

var Rectangle = {
  length: 20,
  width: 20,
  computePerimeter: function(){
    return 2*this.length + 2*this.width;
}

The challenge becomes when we want to create multiple objects which look like this. In OOP, you would use a constructor. In Javascript, you use a function contructor. Which looks like this:

var Rectangle = function(length, width){
  this.length = length;
  this.width = width;
  this.computePerimeter = function(){
    return 2*this.length + 2*this.width;
  }

And to create multiple Rectangles, we use the new keyword:

var babyRectangle = new Rectangle(5, 5);
var longAssMotherFuckingRectangle = new Rectangle(200000, 5);

Turns out, whenever we use this function constructor we end up creating a new function computePerimeter() for every object made using the Shape function constructor. This could be a problem if we made thousands of Rectangle objects. Even worse if we have multiple, BIGGER methods in our function constructor.

Without getting into the whole “protoype” can of worms, functions call(), apply(), and bind() come to the rescue.

Beginning with call() we can now separate our getPerimeter() function from our Rectangle function constructor and use it like such:

var Rectangle = function(length, width){
  this.length = length;
  this.width = width;
}

var computePerimeter = function(){
    return 2*this.length + 2*this.width;
}

var lilRectangle = new Rectangle(2, 3);
var p = getPerimeter.call(lilRectangle);
console.log(p);  // 10

apply() works in a similar way, except it takes an array of arguments if the function requires parameters.

bind() is a little different, and requires a lil more of an understanding of what this means in Javascript and the execution context. So I’ll explain both.

Execution Context

Is the scope of which functions are called. If you create a function like this:

var lmao = function(){ console.log("AHAHAHAHA😂😂😂") }

You can then invoked it like this:

lmao();

You are doing 2 things:

  1. The function you wrote belongs to the global execution context
  2. You are calling it in the global context

So, when we write a function which belongs to an object like this:

var magicNumber = {
  num: 42,
  printNumber: function() {
    return this.num;
  },
};

And invoke it like this:

magicNumber.printNumber();

You are invoking the function printNumber() in the magicNumber execution context.

‘This’

So things are about to get fucked up (like always when it comes to Javascript). For starters, this references the execution context. Lets try some shit out using the command-line so we can see the gears working.

this showing the global object, called in the global execution context

Lets see what happens when we call this inside a function:

printThis() belongs to the global object, therefore this is the global object

What about a function defined inside of an object?

this now refers to uselessObject

This is all expected behavior. Remember: Javascript is an Object-Based language and we can pass basically ANY object as a function parameter, including function objects. We can do funny business such as this:

var arithmetic = function(x, y, operator){
  return operator(x, y);
}

var add = function(x, y){
  return x + y;
}

var multiply = function(x, y){
  return x * y;
}

arithmetic(2, 3, add);      // 5
arithmetic(2, 3, multiply); // 6

Hilarious, in’it? So, what will happen if we pass a function defined in a different object?

var arithmetic = function(x, y, operator){
  return operator(x, y);
}

var magicNumber = { 
  num: 42, 
  addToMagic: function(x, y){ 
                return this.num + x + y 
              } 
};

arithmetic( 8, 0, magicNumber.addToMagic );  //NaN

NaN (Not A Number)? This happened because we invoked arithemtic() in the global execution context, which means that the this keyword will refer to the global execution context. Unfortunately, num is undefined in our global object, which means this function is trying to do: window.num + 8 + 0. And undefined + Number equals to: NaN

If num exists in the global execution context, then it will use that:

2 + 8 + 0 = 10

One way to fix this issue is to define a function constructor, and store the value of this inside a private variable within the object so it can later be used:

var MagicNumber = function() { 
  var that = this;  
  that.num = 42; 
  that.addToMagic = function(x, y){ 
    return that.num + x + y;
  } 
}

Then create an object of type MagicNumber. See a working example of this technique:

Storing ‘this’ in a private variable for later usage

Bind()

Now that we understand this keyword refers to the execution context, we can use that knowledge to understand what bind() does.

bind() binds this to the object supplied in the first argument

Here’s what is happening:

  1. We create a function in the global context
  2. we bind that function to the magic object we created
  3. we execute it in the global execution context, but the value of this is referencing magic object

The result is a function which, no matter where its invoked will reference the magic object when calling this in the function definition.

I’ll be writing more about Javascript explaining other aspects of it such as closures and “prototypal inheritance”.

Similar Posts

Leave a Reply

Your email address will not be published.