问题
What does 'this' keyword refer to when used in gloabl 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("Msg.show()", 1000);
everything work ok.
But if we do something like
AppendEvent(window, 'load', Msg.show);
we get an error because this.rendered is undefined when called from the event scope.
- Do you know why this happens?
- 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?
Thanks!
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:
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 () { Msg.show() } );
There's also the bind method available to functions in ECMAScript 5th Edition implementations, which allow you to do this:
AppendEvent(window, 'load', Msg.show.bind(Msg, 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)));
};
};
}
回答2:
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.
回答3:
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() })
回答4:
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
来源:https://stackoverflow.com/questions/2545588/javascript-using-this-in-global-object