Javascript scope and the “self” argument

Really great post on the Node.js group from “Zhami” (at http://yellowhelium.com/ I believe).  You can see the original post here: http://groups.google.com/group/nodejs/browse_thread/thread/d5c4cefdc255c548

“this” is an interesting entity in JavaScript functions; its value in a function depends on the nature of the function and how the function was invoked. Douglas Crockford describes four invocation patterns [1]. When you see the idiom “var self = this;” [2], most likely the invocation pattern is for a method [3]. In such case, “this” is a reference to the object containing the method. Such an object may have other properties which can be accessed via “this” by dot notation:

e.g., this.propertyName.

JavaScript does not have block scoping, it has function scoping [4]. A variable declared with a var statement (anywhere) within a function has scope within that function and within any (inner) functions declared within that (outer) function. The inner function’s accessing of the value of the outer functions variable is a “closure.” While quite powerful, their use can sometimes bear gotchas, still, they are immensely useful [5].

In a simple (illustrative, not useful) example:

var foo = function (k) {
var i, bar;
i = 3;
bar = function (j) {
i = i + 1;
return i + j;
}
return bar(k);
}

Inner function bar is lexically scoped within outer function foo. Inner function bar can refer to outer function foo’s variables (and arguments). Inner function bar has access to foo’s variable “i” by closure. Any invocation of bar will use the *current* value of i (not
the initially lexically declared value; such mutation of variables accessed by closure is often a source of gotchas with callback functions).

btw: in this simple example, “k” is also accessible to bar, and so doesn’t need to be passed in:

var foo = function (k) {
var i, bar;
i = 3;
bar = function () {
i = i + 1;
return i + k;
}
return bar();
}

Now, consider the case where you have a method of an object that has some properties, and that the method has an inner function which wants to access the value of a property (again, a highly contrived example):


var o = {
i: 3,
bar: function (k) {
var bar;
bar = function () {
i = i + 1;
return i + k;
}
return bar();
}
}

This is created with the expectation that we can invoke:
o.bar(n); // where n is some numeric value
The problem with the above code is that bar has not declared “i” nor is there any variable “i” in its scope chain (i.e., method bar doesn’t declare “i” either) [6]. At first blush you may say, “ah, but ‘this’ in foo refers to the object” and try:

var o = {
i: 3,
bar: function (k) {
var bar;
console.log("i = " + this.i);
bar = function () {
var i = this.i; // gain local access to the property
i = i + 1;
return i + k;
}
return bar();
}
}

But this doesn’t work (double entendre intended).

Presuming that bar is invoked as a method of object o, “this” within foo does provide access to object o’s properties. However, function bar is invoked by the function invocation pattern, and within it, “this” is set to the global context, *not* the object.
So, to make the above concept work, we can create a closure to provide access to the object:


var o = {
i: 3,
bar: function (k) {
var bar,
self = this;
bar = function () {
self.i = self.i + 1;
return self.i + k;
}
return bar();
}
}

In the above, the variable “self” is assigned a value that is a reference to the object. Unless “self” is mutated, it remains a reference to the object. More practical use cases involve callbacks and (often, anonymous) functions:


var o = {
i: 3,
bar: function (k) {
var bar,
self = this;
someAsyncFunction( arg, function (callbackArg) {
// here, "this" is a reference to the global context
// object o properties can be accessed via the "self"
closure, e.g.:
self.i = self.i + 1;
});
}
}

Idiomatically, you may also see “var that = this” and “var me = this”. Personally, I now avoid “self” because, alas, many Browsers define a global “self” variable, and so I have had bugs caused by not declaring “var self = this” when I needed it, yet “self” was defined (arggh).

Note: I have typed all this in and have *not* executed the code, so use at your own risk (lol).

1. “JavaScript: The Good Parts”, http://oreilly.com/catalog/9780596517748

2. Since I minify most of my JS code, I am diligent about including
semicolons.

3. a “method” is a function that is a property of an object.

4. I am appalled by how much JS code I see posted in which coders use
var statements in a way that implies they believe there is block
scope.

5. Clsoures are a good way of creating private object members: see
Stoyan Stefanov “JavaScript Patterns”.

6. Granted, there may be a global variable — but that would be
horrific programming practice.

Proud Noder

Well it’s official:  I’m a Noder.  I spend at least a third of my working hours in Node nowadays and I can’t get enough of it.

Why?

Well, first of all, I took Javascript for granted.  Check out this talk by Douglas Crockford at Yahoo.  Essentially, a Javascript developer can do what would take a traditional programmer (C/Java) much longer to write.   The language supports funky features like closures, anonymous functions, and prototyping (a loose OOP idiom).

Node.js also adopts many useful approaches from CommonJS.

There are so many keen/sharp developers building stuff for Node that production ready apps are right around the corner.

The performance stats are mind numbing.  Ryah Dahl (the creator of Node.js) really proves that event based apps scale much better than thread based.  Node is perfect for running apps with thousands of concurrent connections (see performance charts).

Just a word of warning though if you’re planning on jumping in:  it’s still bleeing edge.  Be prepared for a lack of docs, bugs, and constant changes.  Just the way I like it.

The sooner I move all my technologies and platforms to Node, the happier me and my clients will be.   I’m having a ball rewriting Fresher in Node.  You can expect some big leaps in features and functionality soon…

All over the place…