1

What does 'this' keyword refer to when used in global object?

Let's say for instance we have:

  var SomeGlobalObject =
  {
     rendered: true,
     show: function()
     {
        /*
        I should use 'SomeGlobalObject.rendered' below, otherwise it 
        won't work when called from event scope.
        But it works when called from timer scope!!
        How can this be?
        */
        if(this.rendered)
           alert("hello");
     }
  }

Now if we call in an inline script in the HTML page:

SomeGlobalObject.show();
window.setTimeout("SomeGlobalObject.show()", 1000);

everything works ok.

But if we do something like:

AppendEvent(window, 'load', SomeGlobalObject.show);

we get an error because this.rendered is undefined when called from the event scope.

  1. Do you know why this happens?
  2. Could you explain then if there is another smarter way to do this without having to rewrite every time "SomeGlobalObject.someProperty" into the the SomeGlobalObject code?

AppendEvent is just a simple cross-browser function to append an event, code below, but it does not matter in order to answer the above questions.

  function AppendEvent(html_element, event_name, event_function)
  {
        if(html_element.attachEvent) //IE
           return html_element.attachEvent("on" + event_name, event_function);
        else
           if(html_element.addEventListener) //FF
              html_element.addEventListener(event_name, event_function, false);
  }
1
  • 3
    Ah, JavaScript, your lack of default method binding has claimed its one millionth victim... Commented Mar 30, 2010 at 13:49

4 Answers 4

5

When you reference a function that is a method of an object, you're detaching it from that object and this will no longer be a reference to the object.

The easiest solution is to wrap it in an anonymous function:

AppendEvent(window, 'load', function () { SomeGlobalObject.show() } );

There's also the bind method available to functions in ECMAScript 5th Edition implementations, which allow you to do this:

AppendEvent(window, 'load', SomeGlobalObject.show.bind(SomeGlobalObject, arg1, arg2));

The JS framework, Prototype, provides this method to current JS implementations too. The code (thanks @bobince):

// From Prototype.js
if (!Function.prototype.bind) { // check if native implementation available
  Function.prototype.bind = function(){ 
    var fn = this, args = Array.prototype.slice.call(arguments),
        object = args.shift(); 
    return function(){ 
      return fn.apply(object, 
        args.concat(Array.prototype.slice.call(arguments))); 
    }; 
  };
}
Sign up to request clarification or add additional context in comments.

2 Comments

...or add it yourself if it's missing. stackoverflow.com/questions/2025789/…
@bobince: thanks, I've been looking for that :-) I really need to switch my default search provider back to Google.
1

Do this

var SomeGlobalObject =
  {
     ...
  }

AppendEvent(window, 'load', function(){
    SomeGlobalObject.show();
});

Javascript supports dynamic scoping. So SomeGlobalObject will be available to the function declared inline always.

Comments

0

The this keyword always refers to the calling object. In the first example, SomeGlobalObject is the caller.

I believe you would need to do something like AppendEvent(window, 'load', function() { SomeGlobalObject.show() })

Comments

0

A simple way to describe what happened:

'this' always refers to the invoker of the function.

So take the offending case:

AppendEvent(window, 'load', Msg.show);

Event handling is invoked by the window. So 'this' becomes window and

window.rendered

is undefined.

bind() will quickly become your best friend :-)

As an aside

window.setTimeout("Msg.show()", 1000);

will run a little quicker if you supply the function object directly

window.setTimeout(Msg.show, 1000);

This is because the first syntax requires eval() of the string - basically compiling - before it can be invoked

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.