Saturday 23 August 2014

Javascript - "this" is it.....

In this blog post we will take up one of the most interesting topic in Javascript. Please read this blog post with caution as it comes with a disclaimer.

"this" blew my brains out.......

For all of those like me who are coming to Javascript from any 4G language would know that this refers to the current instance of the object. So say we have a class Employee and we created its instance _employee, now inside any function defined in Employee this will refer to the current instance(_employee).

Well lets say in terms of Javascript above statement is only a part of the truth. In Javascript this is refers to much more. To begin with it this inside a function refers to the object which invoked the function where this is used.

So lets try to make sense of above statement, fire up the chrome console and emit out following snippet.
var person = {
    firstName: 'Bond',
    lastName: 'James',
    showName: function () {
        console.log('Name is ' + this.firstName + ' ' + this.lastName + ' ' + this.firstName);
    }
}
person.showName();//Name is Bond James Bond

1st Golden Rule:
this refers to the value of the object that invoked the function using this

In the example above person invoked the function (showName) and thus this inside showName points to person.

firstName = 'Alpha';
lastName = 'Beta';

 var person = {
     firstName: 'Bond',
     lastName: 'James',
     showName: function () {
         console.log('Name is ' + this.firstName + ' ' + this.lastName + ' ' + this.firstName);
     }
 }

 //called in context of person
 var callfunc = person.showName(); //Name is Bond James Bond


 function showName() {
     console.log('Name is ' + this.firstName + ' ' + this.lastName + ' ' + this.firstName);
 }

 //called function from global context
 showName(); //Name is Alpha Beta Alpha


2nd Golden Rule
this of outer function is not accessible to inner function (for that matter both this and argument of outer function are not accessible to the inner function), it basically points to the global object

var name="pankaj";
var outer={
    name:"lala",
    getNameFunc : function(){
        return function(){
            return this.name;
        };
    },
    getFunc : function(){
        return this.name;
    }
};
   
console.log(outer.getNameFunc()()); //pankaj
console.log(outer.getFunc());     //lala

A bit confusing thus deserve a bit of explanation. Since getNameFunc was invoked with reference to outer we would expect this inside of getNameFunc to refer to outer only and thus lala should be available to same.

Unfortunately this is one of those things in Javascript which is let’s say interesting. I remember getting into discussion with one of my peer if this is a feature of Javascript of behaviour the debate got all heated up until Douglas Crockford came to my rescue.

In his book Javascript the good parts he did mentions that this is a mistake in design of the language, had the language been designed correctly, when the inner function is invoked, this would still be bound to the this variable of the outer function.

A very common workaround for correcting this behaviour is to preserve this of outer function and in the inner function use same instead of this. Doing this will ensure that in which ever context the call is made inner function will always refer to the context of the outer function.

var name="pankaj";
var outer={
    name:"lala",
    getNameFunc : function(){
       var that = this;
        return function(){
            return that.name;
        };
    },
    getFunc : function(){
        return this.name;
    }
};
   
console.log(outer.getNameFunc()()); //pankaj
console.log(outer.getFunc());     //lala

I will explain later why as per me this is a workaround.



Its worth mentioning that a function which is part of an object (which again is a function), it known as the method of the object

3rd Golden Rule

When a method is assigned to a variable, this belongs to the global context

var name ='Pankaj';

var Person ={
    name:'Lala',
    getName: function(){
        return this.name;
    }
}

//getName invoked within context of Person
console.log(Person.getName()); //Lala

//capture the reference of getName in local var
var func = Person.getName;

// getName gets invoked with the context of global
console.log(func()); // Pankaj


4th Golden Rule

For borrowed method, this belongs to the new object

var SimpleCaclulator={
    num1:5,
    num2:5
}

var ComplexCalculator={

    num1:10,
    num2:20,
    add:function(){
        return this.num1+ this.num2;
    }
}

console.log(ComplexCalculator.add()); //30
SimpleCaclulator.add = ComplexCalculator.add; // attching add to SimpleCaclulator
console.log(SimpleCaclulator.add());    // 10 this belongs to SimpleCaclulator

Summary
These sums up the quirks with this in Javascript. We looked at what this means in Javascript, how it should be used. 

We also learned the workaround to avoid falling into these quirks, to mention in coming posts we should be taking about the standard ways to avoid these situations. 

Till then 'this' is it.

No comments:

Post a Comment