4 enlightening rules for this keyword in Javascript

Note : Most of the content is from Kyle Simpson’s book (You Don’t Know JS- this & Object Prototypes) I have modified some things ans well as deleted some to ease my understanding

What’s mystery of this
We said earlier that this is not an author-time binding but a run time
binding. It is contextual based on the conditions of the function’s invocation. this binding has nothing to do with where a function is declared, but has instead everything to do with the manner in which
the function is called. When a function is invoked, an activation record, otherwise known as an execution context, is created. This record contains information about where the function was called from (the call-stack), how the function was invoked, what parameters were passed, etc. One of the properties of this record is the this reference, which will be used for the duration of that function’s execution.

  1. Default binding
    this rule is the default catch-all rule when none of the other rules apply. Consider following code snippet

    function foo() {
    console.log( this.a );
    }
    var a = 2;
    foo(); // 2
    

    The first thing to note, if you were not already aware, is that variables declared in the global scope, as var a = 2 is, are synonymous with global-object properties of the same name. They’re not copies of each other, they are each other. Think of it as two sides of the same coin.
    Second, we see that when foo() is called, this.a resolves to our global variable a. Why? Because in this case, the default binding for this applies to the function call, and so points this at the global object.
    If strict mode is in effect, the global object is not eligible for the
    default binding, so the this is instead set to undefined:

    function foo() {
    "use strict";
    console.log( this.a );
    }
    var a = 2;
    foo(); // TypeError: `this` is `undefined`
    
  2. Implicit Binding
    function foo() {
    console.log( this.a );
    }
    var obj = {
    a: 2,
    foo: foo
    };
    obj.foo(); // 2
    

    at the point that foo() is called, it’s preceeded by an object reference to obj. When there is a context object for a function reference, the implicit binding rule says that it’s that object that should be used for the function call’s this binding. Because obj is the this for the foo() call, this.a is synonymous with obj.a. Only the top/last level of an object property reference chain matters to the call-site.

    function foo() {
    console.log( this.a );
    }
    var obj2 = {
    a: 42,
    foo: foo
    };
    var obj1 = {
    a: 2,
    obj2: obj2
    };
    obj1.obj2.foo(); // 42
    

    One of the most common frustrations that this binding creates is
    when an implicitly bound function loses that binding, which usually
    means it falls back to the default binding of either the global object or undefined, depending on strict mode.

  3. Explicit Binding
    With implicit binding, as we just saw, we had to mutate the object in
    question to include a reference on itself to the function, and use this property function reference to indirectly (implicitly) bind this to the object. But, what if you want to force a function call to use a particular object for the this binding, without putting a property function reference on the object?
    “All” functions in the language have some utilities available to them
    (via their [[Prototype]]—more on that later), which can be useful
    for this task. Specifically, functions have call(..) and apply(..)
    methods. Technically, JavaScript host environments sometimes provide functions that are special enough (a kind way of putting it!) that they do not have such functionality. But those are few. The vast majority of functions provided, and certainly all functions you will create, do have access to call(..) and apply(..). They both take, as their first parameter, an object to use for the this, and then invoke the function with that this specified. Since you are directly stating what you want the this to be, we call it explicit binding.

    function foo() {
    console.log( this.a );
    }
    var obj = {
    a: 2
    };
    foo.call( obj ); // 2
    

    Invoking foo with explicit binding by foo.call(..) allows us to force
    its this to be obj. With respect to this binding, call(..) and apply(..) are identical. The difference is that apply lets you invoke the function with arguments as an array; call requires the parameters be listed explicitly. A useful mnemonic is “A for array and C for comma.”

    function foo() {
    console.log( this.a );
    }
    var obj = {
    a: 2
    };
    var bar = function() {
    foo.call( obj );
    };
    bar(); // 2
    setTimeout( bar, 100 ); // 2
    // hard-bound `bar` can no longer have its `this` overridden
    bar.call( window ); // 2
    

    We create a function bar() which, internally, manually calls foo.call(obj), thereby forcibly invoking foo with obj binding for this. No matter how you later invoke the function bar, it will always manually invoke foo with obj. This binding is both explicit and strong, so we call it hard binding. Since hard binding is such a common pattern, it’s provided with a builtin utility as of ES5, Function.prototype.bind. The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

    function foo(something) {
    console.log( this.a, something );
    return this.a + something;
    }
    var obj = {
    a: 2
    };
    var bar = foo.bind( obj );
    var b = bar( 3 ); // 2 3
    console.log( b ); // 5
    
  4. new Binding

    When a function is invoked with new in front of it, otherwise known
    as a constructor call, the following things are done automatically:
    1. A brand new object is created (aka constructed) out of thin air.
    2. The newly constructed object is [[Prototype]]-linked.
    3. The newly constructed object is set as the this binding for that
    function call.
    4. Unless the function returns its own alternate object, the newinvoked function call will automatically return the newly constructed object.

    function foo(a) {
    this.a = a;
    }
    var bar = new foo( 2 );
    console.log( bar.a ); // 2
    

    By calling foo(..) with new in front of it, we’ve constructed a new
    object and set that new object as the this for the call of foo(..). So
    new is the final way that a function call’s this can be bound. We’ll call this new binding.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s