在javascript中的父闭包中引用“this”

时间:2010-10-26 00:57:21

标签: javascript closures this

我想在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();

可以通过这种方式实现:

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();

有更好的方法吗?

3 个答案:

答案 0 :(得分:6)

保持对父级的引用(就像你一样)是一种很好的方法,但是对于你的具体例子,不需要匿名包装器,你可以直接传递函数,如下所示:

var self = this;
this.b = function()
{
  Z(self.c);
}

You can test it out here,如果没有此包装器,实际上不需要self变量,您可以直接使用this,如下所示:

this.b = function()
{
  Z(this.c);
}

You can test that version here


由于以下评论中似乎存在一些混淆,如果您想维护this /上下文,上面的代码会为问题维护this 回调也是,使用.call() like this

this.b = function()
{
  Z.call(this, this.c);
}

对于Z

function Z( f )
{
  f.call(this);
}

You can test it here

答案 1 :(得分:1)

有一种模式通常被称为“委托”,它解决了这个问题。

在javascript中,一个不太花哨的实现可能看起来像这样:

/** 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(); }
}

在您的示例中,您可以像这样使用它:

this.b = function() {
  Z( Delegate.create(this, this.c) );
}

您还可以编写期望接收代表的函数:

function Z( d ) {
    d.invoke();
}

然后,在A中,b的impl变为:

this.b = function() {
    var d = new Delegate(this, this.c);

    Z( d );
    SomeOtherFunc( d );
}

Delegate只是提供了一种简单,一致的方法来封装this引用(你称之为self),在一个可以像任何其他方式处理的对象实例中对象实例。它更具可读性,它使您不必使用诸如self之类的多余变量来污染您的功能范围。一个更高级的代表实现可以有自己的方法和其他相关的状态。也可以通过这种方式构建委托,以便最大限度地减少与范围相关的内存管理问题(虽然我在这里展示的代码绝对不是一个例子)。

答案 2 :(得分:1)

您也可以使用

this.b = function()
{
    Z( (function () { this.c() }).apply(this) );
}