Referring to "this" in a parent closure in javascript
I want to do this in Javascript:
function Z( f )
{
f();
}
function A()
{
this.b = function()
{
Z( function () { this.c() } );
}
this.c = function()
{
alert('hello world!');
}
}
var foo = new A();
foo.b();
It can be accomplished this way:
function Z( f )
{
f();
}
function A()
{
var self = this;
this.b = function()
{
Z( function () { self.c() } );
}
this.c = function()开发者_运维百科
{
alert('hello world!');
}
}
var foo = new A();
foo.b();
Is there a better way?
Keeping a reference to the parent (like you have) is a good approach, however for your specific example there's no need for the anonymous wrapper, you can pass the function directly, like this:
var self = this;
this.b = function()
{
Z(self.c);
}
You can test it out here, and without this wrapper there's actually no need for the self
variable, you can just use this
directly, like this:
this.b = function()
{
Z(this.c);
}
You can test that version here.
Since there seems to be some confusion in the comments below, the above code maintains this
for the question, if you want to maintain the this
/context inside the callback as well, use .call()
like this:
this.b = function()
{
Z.call(this, this.c);
}
And for Z
:
function Z( f )
{
f.call(this);
}
You can test it here.
You can alternatively use
this.b = function()
{
Z( (function () { this.c() }).apply(this) );
}
There is a pattern that's often called "Delegate", which addresses this issue.
In javascript, a not-too-fancy implementation might look something like this:
/** class Delegate **/
var Delegate = function(thisRef, funcRef, argsArray) {
this.thisRef=thisRef;
this.funcRef=funcRef;
this.argsArray=argsArray;
}
Delegate.prototype.invoke = function() {
this.funcRef.apply(this.thisRef, this.argsArray);
}
/** static function Delegate.create - convenience function **/
Delegate.create = function(thisRef, funcRef, argsArray) {
var d = new Delegate(thisRef, funcRef, argsArray);
return function() { d.invoke(); }
}
In your example, you would use it like this:
this.b = function() {
Z( Delegate.create(this, this.c) );
}
you could also write functions that expect to receive a Delegate:
function Z( d ) {
d.invoke();
}
then, in A
, your impl of b
becomes:
this.b = function() {
var d = new Delegate(this, this.c);
Z( d );
SomeOtherFunc( d );
}
The Delegate
just provides a simple, consistent way of encapsulating the this
reference (which you've called self
), within an object instance that can be dealt with like any other object instance. It's more readable, and it keeps you from having to pollute your function scope with superfluous variables like self
. A fancier delegate implementation could have its own methods and other related state. It's also possible to build the delegate in such a way that it helps to minimize some scope-related memory management problems (though the code I've shown here is definitely not an example of that).
精彩评论