Home Blog News People Projects
Javascript - this binding

this Keyword explained

The this keyword is one of the confusing mechanism in JavaScript. Its confusing as this in JS isn't the same as this in conventional OOP languages. In JS, this could have different meanings depending on the call-site. There are 4 rules for this binding and by inspecting the call-site we can identify the binding.

Let us explore the 4 rules, but before we get started we need some helper functions to understand.

function print_this_a() {
    console.log(this.a);
}
function call_fn(fn) {
    // take a fn as parameter and execute it!
    fn();
}
a = "Global a";

Rule 1 - Default Binding

The first rule we will examine comes from standalone function invocation. Think of this rule as the default catch-all rule when none of the other rules applies. This resolves to the global object, in the browser its the window object.

console.log("(1.0) Default Binding");
print_this_a(); // Output - "Global a"

Rule 2 - Implicit Binding

This rule is applicable when the call-site has a context object or owning object, ie the object owns the function reference at the time the function is called.

obj1 = {
    a: "obj1 a",
    print_this_obj1_a: print_this_a
}

console.log("(2.0) Implicit Binding");
obj1.print_this_obj1_a(); // Output - "obj1 a"

Since the object obj1 owns a reference to print_this_obj1_a and that particular function is invoked through the object reference, this is resolved to obj1

**Implicitly losing context **

console.log("(2.1) Implicitly lost");
call_fn(obj1.print_this_obj1_a); 
// this is no longer obj1 as the function no longer owns the reference

A way to fix this - explicit binding

console.log("(2.2) Calling with call"); 
print_this_a.call(obj1, "var1", "var2"); 
// This is a way to specify the object you want 'this' to resolve to

console.log("(2.3) Calling with apply");
print_this_a.apply(obj1, ["var1", "var2"]);
// Alternative way

Rule 3 - Hard Binding

// Helper fn which allows us to bind functions to specific objects, permanently 
function bind(fn, obj) {
    return function() {
        return fn.apply(obj, arguments);
    };
}

The above function uses the "apply" property discussed in the previous rule. However, this can now be passed across functions and be invoked with the binding intact.

console.log("(3.0) Hardbinding using Binding Helper");
var hard_binded_fn = bind(print_this_a, obj1);
call_fn(hard_binded_fn); // Output - "obj1 a"

ES6 has a built-in bind function, which we can use as follows

console.log("(3.1) Hardbinding using ES6 bind");
var hard_binded_fn_ES6 = print_this_a.bind(obj1);
call_fn(hard_binded_fn_ES6);

Rule 4 - New Binding

JavaScript has a new operator, and the code pattern to use it looks basically identical to what we see in those class-oriented languages. In JS, constructors are just functions that happen to be called with the new operator in front of them. We will discuss more about this in prototypes

function object_constructor(name) {
    this.a = name;
    this.print_this_object_a = print_this_a;
}

object_constructor.prototype.change_a = function(a) {
    this.a = a;
}

obj2 = new object_constructor("obj2_a");
obj3 = new object_constructor("obj3_a");
console.log("(4.0) Calling with new binding");
obj2.print_this_object_a(); //obj2_a"
obj3.print_this_object_a(); //obj3_a"
obj2.change_a("obj2_a_new")
obj3.change_a("obj3_a_new")
obj2.print_this_object_a(); //obj2_a_new"
obj3.print_this_object_a(); //obj3_a_new"

Ignored this

This is unrelated to the above rules, however its a handy feature in JS. It can be useful to create multiple functions which have small differences with each other.

console.log("< --- IGNORED this --- >");
// This can be useful to create functions with pre populated arguments
function print_arguments(){
    console.log( Array.prototype.slice.call(arguments, 0) );
}
console.log("print_arguments in action");
print_arguments(1,2,3); // 1 2 3

console.log("Calling with pre populated arguements");
var fn1 = print_arguments.bind(null,1,2,3);
fn1(); // 1 2 3
fn1(4,5,6); // 1 2 3 4 5 6

Further Reading - “You Don’t Know JS: this & Object Prototypes.”