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.