即使使用修改上下文的函数,也不要修改上下文

时间:2014-09-28 18:34:34

标签: javascript class methods this

也许标题听起来有点奇怪(请改进它) - 但我需要一个针对以下场景的解决方案。我有以下代码:

var Foo = function () {
    this._hello = "world!";
};

Foo.prototype.bar = function () {
    console.log(this._hello);
};

var f = new Foo();
f.bar(); // => "world!"
f.bar.apply(this); // => undefined

我知道apply会更改上下文,因此在bar内部,this将成为全局对象(在第二次调用时)。

但我需要的是从this函数访问Foo。我看到的解决方案是:

var Foo = function () {
   var self = this;
   self._hello = "world!";
   self.bar = function () {
      console.log(self._hello);
   };
};

但是,我会选择不在另一个函数中使用方法声明。

我更喜欢定义相同列级别的方法(仅用于代码样式):

var Foo = ...;
Foo.prototype.method = ...;

这可能吗?怎么样?

2 个答案:

答案 0 :(得分:2)

您可以使用bind() method来解决these kinds of problems。而不是something.method(f.bar)调用something.method(f.bar.bind(f))来始终在预期的上下文(bar)上调用f方法。

如果您不希望在每个传递bind的位置使用bar作为回调,您也可以将它放在构造函数中,为每个实例创建一个专用的绑定函数。默认值:

function Foo() {
    this._hello = "world!";
    this.bar = this.bar.bind(this);
}
Foo.prototype.bar = function () {
    console.log(this._hello);
};

var f = new Foo;
something.method(f.bar); // works!

答案 1 :(得分:0)

通过像这样为原型分配一个函数,不可能做到这一点。

除非您直接为f.bar分配内容(如第二个示例和Bergi的答案),否则您将获得f.bar的值是对您指定的函数的引用原型的属性Foo.prototype.bar。对于以Foo.prototype为原型的任何其他对象,这将是完全相同的函数对象。此函数对象中没有f的引用。

因此,当您致电f.bar()时,this如何引用f的值?它是一种特殊语法,基本上等同于f.bar.apply(f)。只有您使用此方法调用语法才能将this设置为f的值。对f.bar的任何其他引用只会评估原型的单个共享函数对象。

如果您使用f.bar.apply(somethingElse)来呼叫,this现在设置为somethingElse,并且与f的所有关联都将丢失。

这不是apply(...) 更改范围的问题。 fn.apply(x)this内将x设置为fn,而y.fn()this设置为y

同样,在您的示例中,如果您将f.bar分配给变量,然后通过变量调用它而不是使用方法调用语法f.bar(),那么您的this将是{ {1}}对象(如果在浏览器中运行),您将再次获得window

undefined

另见How to find the object a function belongs to?