1

对于 Javascript 新手来说,这可能是一个典型的问题。我确实研究了许多类似的问题,但无法解释我所看到的行为。

下面的代码应该说明我正在尝试做的事情。我有 2 个对象 MyObjectA 和 MyObjectB。

MyObjectB 有一个echo简单地记录消息的方法。它在消息前面加上前缀,this.name试图知道谁在执行该方法。它还打印 的值this

MyObjectA 有一个名为的方法callAFunctionWithMessage正是这样做的。它接受消息和函数并调用它。

在全局范围内,对象被实例化和调用。我看到的this.nameundefined。并且在浏览器中执行时this具有价值DOMWindowObject,并且在 nodejs 中执行时具有一些类似基础设施的大型对象。有人可以帮助我了解这种行为吗?鉴于 MyObjectA 正在调用 echo,我希望“this”指向 MyObjectA。

我也按预期执行指向 MyObjectB 的MyObjectB.echo('hello')位置。this

function MyObjectA(name) {
    this.name=name;
}

MyObjectA.prototype = {
    name : "",
    callAFunctionWithMessage: function (msg, callback) {
        callback(msg);
    }
}

function MyObjectB(name) {
    this.name = name;
    }

MyObjectB.prototype = {
    name :"",
    echo: function(msg) {
        var messageToPrint='[from '+this.name+']'+msg;
        console.log(messageToPrint, " : " + this);
    }
}

var a = new MyObjectA("ObjA");
var b = new MyObjectB("objB");

a.callAFunctionWithMessage('hello from A!', b.echo);
// => [from result]hello from A! : [object Window]

b.echo('hello!');
// => [from objB]hello! : [object Object]
4

3 回答 3

3

当你这样做时:

a.callAFunctionWithMessage('hello from A!', b.echo);

该函数b.echo正在通过全局上下文(在您的情况下为窗口)传递。sothis.name不是对象的 name 属性,a而是name全局上下文的属性,因此您将其视为未定义。您可以改为使用function.binda将其更改为使用自身的上下文调用

 a.callAFunctionWithMessage('hello from A!', b.echo.bind(a)); //now you set the callback with the context of b itself.

在您的情况下,回调方法内部this将代表全局范围。

小提琴

或者通过设置当前上下文来更改调用回调的方式,以确保它采用没有上下文绑定的上下文。

MyObjectA.prototype = {
    name : "",
    callAFunctionWithMessage: function (msg, callback) {
        callback.call(this, msg);
    }
}

小提琴

于 2013-09-23T16:13:49.820 回答
2

当您b.echo作为回调传递时,您传递的函数会丢失它的上下文。有一些简单的规则可以知道这this意味着什么。

  1. 在对象上下文中,它将引用对象实例。
  2. 在对象上下文之外,它将是全局对象(Window)或undefined取决于严格模式。
  3. 如果严格模式生效,this则不会自动解析为全局对象。会的undefined
于 2013-09-23T16:16:30.993 回答
1

The value of this will change depending on how a function is invoked, i.e. what context is it given at invoke time? The only exception to this are bound functions.

I hope the following example will aid your understanding, along with the MDN page for this

function foo() {
    console.log(this);
}

var bar = {
    'foo': foo,
    'baz': function () {foo();}
};

foo();       // -- logs the global object
             //    `foo` was called without context
bar.foo();   // -- logs `bar`
             //    `foo` was called with context `bar`
bar.baz();   // -- logs the global object
             //    `baz` (in context `bar`) called `foo` without context
var x = bar.foo;
x();         // -- logs the global object
             //    `x` was called without context, `x` is still `foo`
x.call(bar); // -- logs `bar`
             //    `x` was called with context `bar`
于 2013-09-23T16:18:29.230 回答