在JavaScript中传递成员时丢失“this”上下文

8
我有一个简单的JSFiddle 这里,展示了我的问题。
我有以下JavaScript代码:
var b = document.getElementById("b");

function A() {
    this.f = "1";
}

A.prototype.t = function() {
    b.innerHTML = this.f;
};

var a = new A();

var l = a.t;
l();

为什么在我尝试调用a.t时this是未定义的?如何在不过于冗长或存储过多的情况下恢复上下文?

3个回答

15

当我试图调用a.t时,为什么会出现未定义的情况?

因为在JavaScript中,this的值主要由函数的调用方式确定,而不是它的定义位置。在a.t()调用中,this被设置为调用时的a,但是在l()调用中,this要么被设置为undefined(在严格模式下),要么被设置为全局对象(在松散模式下)。

更多信息(参见我的博客):

唯一的例外是"绑定"函数(如Function#bind)或ES6的“箭头”函数(它们从定义它们的上下文中获取this)。

如何在不过度冗长或存储过多的情况下恢复该上下文?

Function#bind通常是一个很好的答案:

var l = a.t.bind(a);
l();

它返回一个新函数,当被调用时,会使用你给bind的第一个参数设置this。(你也可以绑定其他参数。)它是一个ES5函数,但如果你需要支持非常旧的浏览器,可以很容易地进行polyfill。


如果你只需要使用特定的this值来调用l,而不总是使用该值,正如Robert Rossmann指出的那样,你可以使用Function#callFunction#apply

l.call(this, 'a', 'b', 'c');    // Calls `l` with `this` set to `a` and args 'a', 'b', and 'c'
l.apply(this, ['a', 'b', 'c']); // Calls `l` with `this` set to `a` and args 'a', 'b', and 'c' -- note they're specified in an array

1
或者,如果该函数不需要传递并且只需调用一次,则可以使用 Function.prototype.callvar l = a.t; l.call(a); - Robert Rossmann
关于原问题提问者的代码,如果在原A函数内部定义了A.t(),这样函数就能够访问私有作用域变量(类似于这样:http://jsfiddle.net/lun471k/re8vdadt/1/)。这种方式是否有效? - Jeff Noel
@RobertRossmann 你能演示一下吗? - eatonphil
@eatonphil: l.call(a) 将使用 a 作为 this,调用 l - T.J. Crowder
1
@JeffNoel:是的。它不会是this,但是是的。然而,它可能是“保留太多”。 - T.J. Crowder

1

JavaScript是函数作用域,

要使用正确的this值执行函数,您需要将其绑定到正确的对象。例如,

var l= a.t.bind(a);

1
但是绑定上下文并不真正与作用域相关。 - Sebastian Simon

1
因为当你将函数分配给一个新变量时,上下文会发生改变。你可以始终使用 a.t();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接