Understanding scope in object oriented JavaScript

JavaScript/Ajax Add comments

When you think of the keyword this you probably assume it refers to the current instance of the class. This is true for most object oriented languages like C# and Java.

For example I could use the this keyword in C# like this:

class Cat {
	string _name;
	public Cat(string name) {
		this._name = name;
	}
}

In the above example you see this illustrated. In C# and Java, this always refers to the class instance.

So, knowing this you would probably assume the same would be true of JavaScript and it’s this keyword. This is, however, not the case. Like a lot of things about writing object oriented code in JavaScript, this behaves differently in some situations. this does not always refer to the class instance depending on how you use it.

function Cat(name) {
	this.Name = name;
}

In the above example it works just like our C# example but let’s look at a situation where things can go wrong if you are unaware of some rules.

var wrong = new WrongClass();
wrong.publicMethod();

function WrongClass() {
	this.publicProperty = 'props';
	this.publicMethod = function() {
		console.log('public method');
		privateMethod();
	};
	var privateMethod = function() {
		console.log('private method');
		console.log('public property equals ' + this.publicProperty);
	};
}

In my examples I am using the console object of Firebug to output my data.

So what is wrong with the above example? It looks like everything should work, right? Well, operating on the assumption that this always refers to class instance then the above code would be correct. We are, however, using JavaScript and shouldn’t be that surprised that it does things a little differently.

The output when publicMethod() is called would be:

>>> public method
>>> private method
>>> public property equals undefined

The reason this.publicProperty is undefined is because when entering the private method the scope of this changed. It no longer means the current instance of the class ‘WrongClass’ but it now means the current instance of the function ‘privateMethod’.

Another situation where the scope of this would change is when dealing with event handlers.

document.getElementById('button').onclick = function() {
	alert(this.id);
}

In the above example this would refer to the instance of the document element ‘button’. There are many cases of scope change that you need to be aware of when dealing with object oriented techniques.

Back to our ‘WrongClass’ example. I’ll show you how to make that example work the way you would have expected it to work in the first place.

var right = new RightClass();
right.publicMethod();

function RightClass() {
	var self = this;
	this.publicProperty = 'props';
	this.publicMethod = function() {
		console.log('public method');
		privateMethod();
	};
	var privateMethod = function() {
		console.log('private method');
		console.log('public property equals ' + self.publicProperty);
	};
}

You’ll see that in the above code I have declared a variable called self. I assign this to this variable. This allows me to then use ’self’ any time I want to refer to the class instance without worrying about scope.

You can call your variable anything you like but ’self’ seems to be a common practice. So, now in ‘privateMethod’ when ‘publicProperty’ is called using ’self’ it will output the proper value.

>>> public method
>>> private method
>>> public property equals props

kick it on DotNetKicks.com

Did You Enjoy This Post?

Be sure to grab my RSS feed so you don't miss out on more great articles.

This Post Was Brought To You By

How do I save time? I use FreshBooks for invoicing.

Get Information Technology magazine subscriptions and white papers for FREE!

Understanding scope in object oriented JavaScript

13 Responses to “Understanding scope in object oriented JavaScript”

  1. Oliver Says:

    “It no longer means the current instance of the class ‘WrongClass’ but it now means the current instance of the function ‘privateMethod’.”

    That’s not strictly true as a function instance never has an instance per se. At that point the this object will be the global object. When you call a function in the form

    someExpression.someFunction()

    then the result of someExpression will be used as the this object. When you call a function with the form

    someFunction()

    Then determining the this object is more complex. The first thing that needs to happen is finding the function. This is done by walking the scope chain until we reach the point where ’someFunction’ is defined.

    Now here’s the fun bit, if this entry in the scope chain is a real object then we use that object as ‘this’. Objects can get into the scope chain in two ways. The most obvious is the global object, which is the first entry in the scope chain, the other is through the use of ‘with’.

    But in the more normal case (which you’re describing) you aren’t using ‘with’ so what happens? We’ll find the function, but the scope chain entry won’t be a real object so we don’t have anything we can use as “this”. So the global object is substituted for this instead, which results in the behaviour you’re describing:D

  2. Jaisen Says:

    You can also access publicProperty by omitting the this keyword altogether. Defining the private method creates a closure with access to other properties of the “class”.

    However, assigning this to self is much clearer. I like it :).

  3. Yoan Says:

    There is a big issue with that pattern. The function are attached to the object and not the class (prototype) so each time you create a new object, you duplicate them in memory.

    Find there a revealing class pattern:

    http://pastie.org/205243

    which handles private/public inside the prototype.

  4. Justin Says:

    @Yoan,

    Thanks for the great link that is a great bit of code. My goal was to point out some scope issues and I wanted to use code that was easy to understand and looked similar to what you might see in Java or C#. You are correct that it is not the most efficient approach, however unless used on a large scale there shouldn’t be an noticeable side effects especially if you do any memory management in your code.

  5. Oliver Says:

    @Yoan: you only duplicate that function object, not the code itself, which isn’t that significant. In fact most strings would likely result in more memory usage than a single function reference, so yes that is more memory being used, but the other issue is runtime performance. If the function is place on the prototype then any access to that function will require at least two property lookups (first on the object, then the object’s prototype), and that property look up is not cheap.

    Obviously the tradeoff would depend on the application, if you’re going to make 4 million of these objects, and then call the function once the storing on the prototype makes sense, although obviously the reverse situation it would make sense to go the other way.

  6. kangax Says:

    @Oliver

    You seem to be confused about the way “context” is set in JavaScript.
    What “this” keyword refers to is determined solely based on the way function was invoked.
    This has nothing to do with function scope, “with” statement or the way function is defined.

    There are 4 patterns of invocation:

    function invocation - “foo()” - this refers to a global object;

    method invocation - “foo.bar()” - this refers to a base object (”foo”);

    contructor invocation - “new foo()” - this refers to an instance object;

    apply invocation - “foo.apply(bar)/foo.call(bar)” - this refers to specified object - “bar” in this case;

    Cheers,
    kangax

  7. Buu Nguyen Says:

    >> It no longer means the current instance
    >> of the class ‘WrongClass’ but it now
    >> means the current instance of the
    >> function ‘privateMethod’.
    Well, ‘this’ in privateMethod’s context should be the instance of Window object.

    And if you want to refer to the expected ‘this’, this is a shorter way:

    this.publicMethod = function() {
    console.log(’public method’);
    privateMethod.call(this);
    };

  8. Justin Says:

    @Buu,

    Thanks for the tip. It is a good point. In a situation where I might have multiple private methods I would prefer to use the way I outlined in the article. IMO it is more readable and easier to understand what is going on if one is not familiar with different approaches available in javascript.

    It’s a matter of personal preference.

  9. Oliver Says:

    @kangax: That’s unlikely given that i work on one of the major implementations :D
    * a.b(), a will be this
    * a[”b”](), b will b this
    * a.apply/call, this will be the specified value
    * b() — and this is the case where resolution of the this value is dependent on scope

  10. Oliver Says:

    @akngax: whoops, first sentence is slightly harsher than i meant it to be, my apologies. However the sections of relevance in the spec are 11.2.3 and 10.2.3 of ecma 262.

  11. Oliver Says:

    @kangax: Hmmm, maybe you’re thinking of “with” such that
    with(a)
    b()

    is equivalent to
    if (a.b)
    a.b()
    else
    b()

    (Despite no implementation actually doing this trnasformation, it should be identical in behaviour to what is expected)

  12. kangax Says:

    @Oliver

    I couldn’t reproduce “a[”b”](), b will b this”. “this” still points to a “base” object (i.e. a).

    Out of curiosity, which “major implementation” are you working on?

  13. things to look at (June 23rd) | stimulant - changing things around. . . Says:

    […] Geek Daily » Blog Archive » Understanding scope in object oriented JavaScript […]

Leave a Reply

WP Theme & Icons by N.Design Studio
Entries RSS Login