Search code examples
javascriptprogramming-languagesfunctional-programming

Why 'this' resolution is so special in JavaScript?


Warning: Buggy JavaScript code first!

// 1: buggy counter
// -----------------
// problem: 'this' can be "broken"
var Counter1 = function() {
    this.count = 0;
    this.increment = function() {
        function increment_helper(){
            ++this.count; // this refers to window (global), not to the object that Counter1 was called with
        }
        increment_helper();
    }
    this.reset = function() { this.count = 0; }
    this.get_count = function() { return this.count; }
}

var counter1 = new Counter1();
counter1.increment();
document.writeln("<p> 1: " + counter1.get_count() + "</p>");

As it can be seen, the this in increment_helper rather refers to the global scope (or to window scope to be precise IF I've got it right) instead of referring to the this of the enclosing closure. So that, the output will be:

0

instead of

1

I'll list the better (still not perfect, but okay) solution and then will ask the main question. So, the solution (IMHO) can be sorted out like this:

// 2: better counter
// -----------------
// solved: 'that' can't be "broken"
var Counter2 = function() {
    var that = this;
    that.count = 0;
    that.increment = function() {
        function increment_helper(){
            ++that.count; // that refers right to the object the Counter1 was called with
        }
        increment_helper();
    }
    that.reset = function() { that.count = 0; }
    that.get_count = function() { return that.count; }
}

var counter2 = new Counter2();
counter2.increment();
document.writeln("<p> 2: " + counter2.get_count() + "</p>");

So, the main question is: why this is special like noone else in JavaScript? Why it's only this and for what purpose?

Thanks a lot!

Update: Following @Jordan's comment below (where he explained the difference between relative variables like this and scoped variables like regular ones), rephrasing my questions:

A: what is the general rationale behind relative variables?

B: why this is the only relative variable in JavaScript? Any rationale on why the relative/scoped concept can be (exclusively) applied to every variable?


Solution

  • A. In JavaScript, unlike in other C-like OO languages, functions are first class objects. You can copy functions around, pass them into other functions, return them from functions, create new ones. Functions are not like methods in Java or C# that are permanently affixed to the class declaration. This means that this has to be relative to the function itself and how it was called. It doesn't make sense otherwise.

    So as a silly example:

    var o = {
      name: "My name is o",
      foo: function () { alert(this.name); }
    };
    
    var p = {
      name: "My name is p",
    };
    
    p.foo = o.foo;
    p.foo(); // "My name is p"
    

    That can't be done in other OO C-type languages, but it can in JavaScript. Hence this has to be relative. Yes, it causes problems, but the language becomes incredibly expressive with it.

    B. arguments is also relative.