More on this in JavaScript

There’s more to this in JavaScript than I showed last time. Time for more details on methods, closures and the global object.

This is a direct continuation of the this in JavaScript vs C# post. If you haven’t already read it, I suggest that you read it before continuing here.

More on Methods

Last time I finished with a code example with a method that allowed me to receive payments and show my current cash level. In this post I’ll add the same function as a method to another object.

// Repeated from old post
var mySelf = {};
mySelf["name"] = "Anders";
 
var getPayment = function (amount) {
  // Initialize to 0 if no cash property.
  this.cash = (this.cash || 0) + amount;
};
 
var showCash = function() { 
  document.write("Current " + this.name + " cash: " + this.cash + "<br/>"); 
};
 
mySelf.getPayment = getPayment;
mySelf.showCash = showCash;
mySelf.getPayment(10);
mySelf.showCash();
 
// New content
computerShop = { getPayment: getPayment, showCash: showCash, name: "Computers inc." };
computerShop.getPayment(100);
computerShop.showCash();

The computerShop reuses the getPayment and showCash functions as methods. Now, the same function is used as a method of two distinct different objects. The function will receive the current object as this, thanks to this being bound by the method invocation rather than being tied to the object.

The Global Object

What if the function is called directly – we have a reference to it in the getPayment variable?

getPayment(42);
showCash();

The output to the document shows that the value is indeed stored between the function invocations:

Current cash: 42

To be able to store a value, the functions use this. Even though the functions were not called as a method, this was valid.

In JavaScript there always is a this. If nothing else is specified this is the global object (the same as where global variables are kept).

cash = 17;
showCash();

This will now show the cash value as 17 instead. Using the global object is of course discouraged. Global variables are a code smell in any language as it is inevitable with name collisions in large programs. The JavaScript way to define modules is to use closures. I won’t go into details on closures for module creation now, but I will show an important difference in closure handling between C# and JavaScript.

Closures

A closure is the possibility for an inner function to access the outer function’s variables (even if the outer function has already returned). So far C# and JavaScript are equal. When it comes to this handling they behave different, which is important to know to avoid nasty surprises.

In C#, an inner function has access to this of the outer function.

class C
{
  int i = 0;
  public void F()
  {
    Action a = () => this.i = 42;
    a();
    Console.WriteLine(i);
  }
}

Calling F() will print out 42. The corresponding JavaScript code is valid. But it won’t do the same.

var o = {
  i : 0,
  F : function() {
    var a = function() { this.i = 42; };
    a();
    document.write(this.i);
  }
};
o.F();

The output to the document will be “0”. The inner function is indeed called, but it won’t receive a reference to o as this. Remember that it is how the function is called that decides the value of this. If it is not called with method syntax, this will be the global object. We just created a new global variable i with the value 42.

Manually Passing this

There is a way to handle the last example: By using the JavaScript apply or call functions (the difference is how arguments are passed, in this example there are no arguments so both work the same). The closest relative in C# is extension methods, where the this parameter is passed in explicitly.

var p = {
  i : 0,
  F : function() {
    var a = function() { this.i = 42; };
    a.apply(this);
    document.write(this.i);
  }
};
 
p.F();

That last example will print out 42.

Capturing this in that

In the previous example this was passed directly by using the apply method. In many cases that approach is not possible, i.e. when passing a function to be used later as a callback by some library. In that case the convention is to capture this into a variable that for usage in the inner function.

var q = {
  i: 0,
  F: function F() {
    var that = this;
    var a = function () {
      that.i = 42;
    }
    a();
    document.write(this.i);
  }
}
 
q.F();

JavaScript is not C#

JavaScript is definitely a powerful language, but it is not at all as similar to C# as the syntax suggests. I’ll continue reading JavaScript: The Good Parts to learn more about it. Chances are that there will be more blog posts.

The links to Amazon in this post are sponsored.

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.