

An Introduction to JavaScript's "this" - jmtulloss
http://justin.harmonize.fm/index.php/2009/09/an-introduction-to-javascripts-this/

======
Bluem00
This article does a good job of explaining a concept I had trouble with when
first using javascript. Now, I usually use the approach recommended in the
article of setting a private variable (e.g. self, or my) to the current value
of 'this' in a javascript class.

However, I think the article is slightly incorrect on one minor point. It
states, "this wants to be window whenever possible, which is not always what
you want." I believe the correct description is: the 'this' variable in a
function called in response to an event on dom object is set to that dom
object. For the example given in the article, this is set to the window object
because setTimeout causes an event on window to fire, not because there's any
inherent preference for the window object.

~~~
aboodman
There is indeed a preference for window (really the global) object. Try these:

<script> alert(this == window); function foo() { alert(this == window); }
foo(); </script>

|this| is basically a magical variable that by default is set to the global
object, but can also be set by the caller of a function one of two ways:

a) by setting a reference to the function on an object, and calling it with
object or bracket notation: var someObj = {}; someObj.f = theFunction;
someObj.f(); // now |this| inside theFunction will // point to someObj
someObj["f"](); // same thing

b) by using apply: theFunction.apply(someObj);

You are right that in the case of event handlers, it is common in the DOM for
event handlers to get their |this| set to the DOM node that fired the event.
Since the default value of |this| is the global object, it isn't possible in
the case of setTimeout for us to tell whether the caller (the host) explicitly
set it, or if the function is being called without any value set for |this|.

Basically, |this| is an extra parameter to any function. It is controlled by
the caller, and as such, should either be documented as part of the signature
of the function, or else should not be relied on by the implementation of the
function.

The common misunderstanding with people new to JS is that they expect |this|
to be controlled by the callee, like it is in lots of other popular languages,
and are surprised when calling convention can change its value.

~~~
aboodman
BTW, imo, the behavior of |this| is a really unfortunate design flaw of JS.
The amount of time that must have been spent learning and teaching this edge
case over and over to every person new to the language is ... well, it's big.

~~~
vicaya
The behavior of 'this' is from DOM bindings and not from the language per se.
Javascript can set 'this' of any calling context to any object with 'apply' or
'call'. The convention for on* handlers is that 'this' is set to the DOM
element when the handlers are called. I only learned to appreciate this, when
I wrote my own little JS DOM framework a la JQuery or Dojo.

~~~
litewulf
I believe actually that 'this' points to the global object.

So if there is no obvious thing for this to point at, it'll point at the
global object. Its just implementation detail that in browsers it points to
the window object.

------
mhansen
The way I remember it: this is whatever is before the dot when you call the
function.

E.g. for car.drive(); in the drive function, any reference to 'this' will get
'car'. If the function is called on it's own, as in 'drive()', 'this' will
refer to the Global object (bad)

It's also possible to change 'this' by using the Function.prototype.apply()
method, which allows you to pass a 'context' parameter that will become
'this'.

------
kwamenum86
The function: setTimeout(30, function() {
myHotDog.getCondiments.apply(myHotDog); });

can actually just be: setTimeout(30, function() { myHotDog.getCondiments();
});

apply is definitely useful but it just makes the code more verbose in this
case.

~~~
nixy
Which JS engine allows you to call setTimeout like that? Isn't
setTimeout(expression, timeInMs [, args]) the right way to go?

~~~
bouncingsoul
That's correct, but the optional args parameter isn't supported in IE. So if
you want to use setTimeout or setInterval to call a function with arguments
you have to do it as an anonymous function with your function call inside.

You're right though that milliseconds should be the second argument, not the
first.

<https://developer.mozilla.org/En/Window.setTimeout>

------
judofyr
Is this supposed to be Ruby?

    
    
        class HotDog:
             condiments
             def getCondiments
                  return @condiments // @ is a reference to the current instance of HotDog.
             end
        end

~~~
jmtulloss
sorry, that was typed up pretty quickly, and I'm not a rubyist... care to
correct it?

~~~
jhancock

      class HotDog
             @condiments
             def getCondiments
                  return @condiments // @condiments is an instance variable of an instance of HotDog
             end
        end
    

note the mod to both the ivar def and the comment. You also do not need the
initial ivar "definition" as ruby defines them on the fly when they are first
referenced.

~~~
xtho
No,

The first @condiments would define a class variable.

    
    
        class HotDog
            attr_accessor :condiments
        end
    

Or for Java-socialized folks:

    
    
        class HotDog
             def initialize
                 @condiments = nil
             end
    
             def getCondiments
                  return @condiments
             end
        end

~~~
jhancock
oops, sorry. yes, the first line would define a "class instance" variable.

btw, I didn't show the attr_accessor meta-programming sine it hides the guts
of the excercise.

------
axod
It's not a quirk, it doesn't need "fixing". Get a good javascript book. Still
surprising how many people try to learn js by feeling around in the dark or by
googling.

~~~
jmtulloss
I absolutely agree. I tried to put "fixing" in quotes as much as possible.
However, you have to see that for many programmers, it is unexpected behavior.
In the eyes of many UI specialists, unexpected behavior is the definition of a
quirk. JS fanatics have to be accepting of the fact that JS is not a regular
language that follows "regular" rules.

~~~
axod
Sure, I agree... And if you go in #javascript on freenode for a few minutes,
you'll see endless questions about why their event handler doesn't work.
Endless answers "use a closure".

I just wish people would read a book on the language first, then the behavior
would be pretty obvious and expected.

------
trjordan
Does anybody have a mirror? It appears to be down for me.

~~~
_ck_
<http://addons.mozilla.org/en-US/firefox/addon/2570>

oh and

[http://google.com/search?q=cache:http%3A%2F%2Fjustin.harmoni...](http://google.com/search?q=cache:http%3A%2F%2Fjustin.harmonize.fm%2Findex.php%2F2009%2F09%2Fan-
introduction-to-javascripts-this%2F)

------
diN0bot
one neat way to define a class is like so:

    
    
      function MyClass(a, b) {
    	// use this function as an instance constructor
    	// eg, var m = new MyClass('foo', 'bar');
    	this.a = a;
    	this.b = b;
      }
      MyClass.prototype = {};
      _extend(MyClass.prototype, {
    	instanceMethod: function() {
    		...
    	},
    	...
      });

------
volida
This article is wrong. You need to use prototype when defining your functions.

Here is how to do it:

    
    
      <html>
      <head>
      <script>
    
      function HotDog () {
    	this.name=arguments[0];
      } 
    
      HotDog.prototype.name=null;
    
      HotDog.prototype.getCondiments= function () { 
    	document.getElementById('test').innerHTML='started...'  +this.name;
      };
      var myHotDog = new HotDog('test 001');
    
      window.onload= function() {
    	setTimeout(30, myHotDog.getCondiments());
      };
    
      </script>
    
      </head>
      <body>
      <div id=test>loading...</div>
      </body>
      </html>

~~~
jmtulloss
I would never not use a prototype in production code, but prototypes are a
different topic that I wanted to avoid for this article. I'm just trying to
explain "this".

Also, your code isn't right. You're calling myHotDog.getCondiments instead of
passing a reference to setTimeout.

~~~
volida
Sorry, I wasn't clear enough. I didn't mean what you are explaining is wrong.

