Javascript - The this keyword

javascript

http://blogs.sitepoint.com/2011/02/25/what-is-this-in-javascript/
http://blogs.sitepoint.com/2011/03/16/javascript-this-gotchas/
http://www.sitepoint.com/inner-workings-javascripts-this-keyword
http://www.quirksmode.org/js/this.html
http://stackoverflow.com/questions/6149402/preserving-this-inside-instance-object-of-class
http://stackoverflow.com/questions/2025789/preserving-a-reference-to-this-in-javascript-prototype-functions
http://stackoverflow.com/questions/3630465/preserving-the-functions-scope-when-using-function-apply
http://net.tutsplus.com/tutorials/javascript-ajax/fully-understanding-the-this-keyword/
http://www.sitepoint.com/mastering-javascripts-this-keyword

// JavaScript - this:
1. In the global context or inside a function this refers to the window object.
2. Inside IIFE (immediate invoking function) if you use "use strict", value of 
   this is undefined. To pass access window inside IIFE with "use strict", you 
   have to pass this.
3. While executing a function in the context of an object, the object becomes 
   the value of this
4. Inside a setTimeout function, the value of this is the window object.
5. If you use a constructor (by using new keyword) to create an object, the 
   value of this will refer to the newly created object.
6. You can set the value of this to any arbitrary object by passing the object 
   as the first parameter of bind, call or apply
7. For dom event handler, value of this would be the element that fired the event

What is the purpose of the this keyword?

Within JavaScript, your code will always have a context (an object within which it is operating). This is a common feature of other object-oriented languages too, but without the extreme in which JavaScript takes it. The way context works is through the this variable. The this variable will always refers to the object that the code is currently inside of. In global context, the this variable still refers to an object (the window object).

// Examples of using functions within context and then switching its
// context to another variable
var obj = {
  yes: function() {
    // this == obj
    this.val = true;
  },
  no: function() {
    this.val = false;
  }
};

// We see that there is no val property on the obj object
alert( obj.val == null );

// We run the yes function, and it changes the val property
// associated with the 'obj' object
obj.yes();
alert( obj.val == true );

// However, we now point window.no to the obj.no method and run it
window.no = obj.no;
window.no();

// This results in the obj object staying the same (because the context was
// switched to the window object)
alert( obj.val == true );

// and window val property got updated
alert( window.val == false );

The method of switching context, as shown above, may not be ideal (you may not want to permanently assign obj.no to window.no).

// Examples of using .call and .apply for changing the context of a function
// A simple function that sets the color of its context
function changeColor( color ) {
  this.style.color = color;
}

// Calling it on the window object, which fails, because it doesn't have a style object
changeColor( "white" );

// Find the element with an ID of main
var main = document.getElementById("main");

// Set its color to black, using the call method
// The call method sets the context with the first argument
// and passes all the other arguments as arguments to the function
changeColor.call(main, "black");

// A function that sets the color on the body element
function setBodyColor() {
  // The apply method sets the context to the body element
  // with the first argument, the second argument is an array
  // of arguments that gets passed to the function
  changeColor.apply( document.body, arguments );
}

// Set the background color of the body to blacks
setBodyColor( "black" );

What does 'this' refer to in the function doSomething()?:

function doSomething() {
    this.style.color = '#cc0000';
}

In javascript, 'this' always referer to the owner of the function (the object that a function is a method of). When we define a function in a page, its owner is the page (the window object). An onclick property is owned by the html element it belong to.

So if we want to use 'this' to its full extent we have to take care that the function is owned by the correct HTML element In other words, we have to copy the function to our onclick property:

element.onclick = doSomething;

The function is copied in its entirety to the onclick property (which now becomes a method). So if the event handler is executed, 'this' refers to the HTML element and its color is changed. We can copy the function to several event handlers. Each time 'this' will refer to the correct HTML element (that owns the copy of doSomething). However, if you use inline event registration:

<element onclick="doSomething()">

you do not copy the function! Instead, the browser creates a wrapper function which call doSomething(), and the difference is crucial. When we arrive at doSomething() the 'this' keyword once again refers to the global window object and the function returns error messages. If you do:

element.onclick = doSomething;
alert(element.onclick)

you get

function doSomething()
{
    this.style.color = '#cc0000';
}

As you can see the 'this' keyword is present in the onclick method, therefore it refers to the HTML element. But if you do

<element onclick="doSomething()">
alert(element.onclick)

you get

function onclick()
{
    doSomething()
}

This is creating a wrapper function which call doSomething(). The 'this' keyword is not present in the onclick method so it doesn't refer to the HTML element. With inline registration, you can have:

<element onclick="any arbitrary javascript code">

and the browser take "any arbitrary javascript code" and wrap a function around it.

In class-based OO languages, the this pointer generally references the instances of the class within which the method had been declared. In JavaScript, where functions are first-class objects that aren't declared as part of anything, the object referenced by the this keyword, termed the function context, is determined not by how the function is declared, but by how it is invoked. This means that the same function can have different contexts depending on how it's called.

When the function is called directly as a top-level function, the function context is the window object. When called as a property of an object, the object becomes the context of the function invocation. We would says that the function acts as a method for that object.

The function context is determined on a per invocation basis, and a single function can be called with any object acting as its context using the .call and .apply methods. It is therefore, probably never correct to say that a function is a method of an object. It's much more correct to say that "A function f acts as a method of object O when O serves as the function context of the invocation of f".

It is not how a function is declared, but how it is invoked that determine its context.

When using inline event registration, how can we send 'this' to the function?

<element onclick="doSomething(this)">
function doSomething(obj) {
    obj.style.color = '#cc0000';
}
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License