What is and how does context (this) work in Javascript?

Asked

Viewed 3,182 times

20

Essential part of Javascript, every function has context (this). How it works, how to manipulate it and what changes in strictly speaking ('use strict')?

  • There will be a bonus for the best answer.

  • 2

    By "context" you mean the value of this? I ask because "context" is a term often used for this, but it is not the term used in language specification.

  • @bfavaretto Interesting observation, yes, I speak of the this in this question, the term context is used by Douglas Crockford and ended up deriving in other books conceptualized as the Javascript The Definitive Guide for David Flanagan

1 answer

27


In Javascript, the execution context of a code snippet - which defines its lexical scope, among other things - has a property called ThisBinding, which can be accessed at any time through the keyword this. This property - present even when it is not within a function and/or this function is not an object method - is popularly known as the context [of function].

Initially (i.e. in "top-level") the this corresponds to a reference to the global object. In browsers, it is called window, and is self-reference. When interpreting a code through eval, he is kept as he is. When calling a function, it changes as follows:

  • If this function is called in the form of a method (i.e. name, point, name, parentheses) this becomes a reference to the object that was "target" of the call:

    obj.f(); // Dentro de "f", this === obj
    

    As pointed out by @bfavaretto, if the object is a primitive type (like a number), then the this may be coerced into an object. This does not occur in strict mode.

    Number.prototype.foo = function() { 
        console.log(typeof this);
    }
    10.0.foo(); // "number" no modo estrito, "object" caso contrário
    
  • If one of the methods is used call, apply or bind, the this is explicitly assigned:

    f.call(obj, foo, bar); // Dentro de "f", this === obj
    f.apply(obj, [foo]);   // idem
    f.bind(obj);           // idem
    

    This is also worth that the function has been referenced in the form of "an object method":

    obj.f.call(bar); // Dentro de "f", this === bar
    

    In strict mode, what is passed as the first parameter will be the this, without modification. Otherwise, there may be the same coercion to the previously mentioned object or, if the value passed as parameter is null or undefined, the this returns to be the global object:

    f.call(20);   // 20 no modo estrito, Number(20) caso contrário
    f.call(null); // null no modo estrito, window caso contrário
    f.call();     // undefined no modo estrito, window caso contrário
    
  • If the function is called in the "normal" form (i.e. name, parentheses), then of the two:

    • In the strict way, this will be undefined:

      "use strict";
      f(); // Dentro de "f", this === undefined
      
    • In other cases, this is again a reference to the global object:

      f(); // Dentro de "f", this === window
      

      ...which often causes confusion:

      var obj = {
          f:function() {
              function g() {
                  console.log(this); // this não é obj, e sim window ou undefined
                                     // (conforme o modo, estrito ou não)
              }
              g(); // Espera-se que imprima "obj", mas não é o que ocorre
          }
      }
      

The main form of context manipulation, as has already been seen, is through the methods call, apply and bind. The latter creates a "view" of the original function where the this is "tied" to the parameter used, and cannot be modified (a kind of currying, also allowing to fix the first N arguments) - not even by the other methods:

function f() {
    console.log(this);
}
var x = f.bind(10); // this está amarrado a 10
x.call(20);         // não muda o this, ainda imprime 10

As for the strict mode, the main impact in this context is the one above - where the this does not refer to the global object when omitted (i.e. when not explicitly assigned). This has an impact on security as it facilitates isolation (sandboxing) not totally reliable code. There many other impacts that the strict mode exerts on contexts of execution and scope, but nothing that affects the functioning of the this (even the eval continues to behave the same way in both ways).

jsFiddle with all the above examples.

  • 1

    Nor will I answer :)

  • 2

    I think there was only one detail missing, which I remembered by reading your last example: if this is a primitive value, it suffers coercion to object (in the case of its example, to Number); in the Strict mode, but there is no coercion.

  • Complementing, this is in the Section 10.4.3 of specification.

  • @bfavaretto hehe if the question was about execution contexts (and not only about the this), I was going to leave it to those who know more... P (P.S. well remembered about coercion! i knew this was done in normal mode, but not that in Strict mode it was different)

  • +1 you write very well, your explanation is succinct and well complete. I was going to auto-reply, but after that I see no need hehe

Browser other questions tagged

You are not signed in. Login or sign up in order to post.