JavaScript : when B inherits from A, callbacks in A cannot see B
Cannot figure out how to get access to the "extended" properties of a child object from a callback in the parent. My two attempts are below. I would like for the function "say_something" to alert "say hi", where "hi" comes from the child. Instead, it says "say undefined".
Attempt 1 : I create an object "a", then create a new object "b" that derives from it. But a callback in "a" (here from a setTimeout) won't have access to the correct "this".
var a = {};
a.say_something = function () { setTimeout( function () { alert( "say " + this.text ); }, 0 ); };
var b = Object.create( a );
b.text = "hi";
b.say_something(); // alerts "say undefined"
Attempt 2 : Common wisdom says re-arrange to allow for a "that" variable which can be accessed in the callback. But unlike "this", "that" cannot access properties from "b" :
var a = ( function () {
var that = {};
that.say_something = function () { setTimeout( function () { alert( "say " + that.text ); }, 0 ); };
return that;
}() );
var b = ( function () {
var that = Object.create( a );
that.text = "hi";
return that;
}() );
b.say_something(); // alerts "say undefined"
PS, I use Douglas Crockford's Object.create function instead of the (confusing to me) new(). It is copied here:
if ( typeof开发者_运维技巧 Object.create !== "function" ) {
Object.create = function ( o ) {
function F() {}
F.prototype = o;
return new F();
};
}
If you add
a.say_something();
to you first example it will also return say undefined
. The problem is that setTimeout
does not execute the code it calls in the scope in which it is called.
We can solve this by either:
- Hard-coding a reference to the existing object
alert('say ' + a.text);
- Using
call()
andapply()
to specify the context in which the function should execute. (Andbind()
too -- for the newest platforms.)
Approach #2 is what you are looking for.
var a = {};
a.text = "hello!";
function say_something() {
var that = this; // Save the reference to *this* this.
setTimeout( function() { console.log.call(that, "say " + that.text ); }, 0 );
}
a.say_something = say_something;
a.say_something(); // say hello!
var b = ( function () {
var that = Object.create( a );
that.text = "hi there!";
return that;
}() );
b.say_something(); // say hi there!
In a setTimeout function, "this" always refers to the Window object.
What I usually do is something like (tested and works)
a.say_something = function () {
var thisObj = this;
setTimeout(function () {
alert( "say " + thisObj.text );
}, 0 );
};
精彩评论