Stoyan Stefanov:JavaScript模式 - 回调和范围

时间:2014-02-05 16:33:44

标签: javascript design-patterns callback this

在“回调和范围”部分的第4章(功能)中,您可以找到以下示例:

var myapp = {};
myapp.color = "green";
myapp.paint = function (node) {
    node.style.color = this.color;
};

var findNodes = function (callback) {
    // ...
    if (typeof callback === "function") {
        callback(found);
    }
    // ...
};

在我的这本(e-)书的版本中,作者写道:

“如果你调用findNodes(myapp.paint),它将无法按预期工作,因为不会定义this.color。这将引用全局对象的对象,因为findNodes()被调用为函数,如果将findNodes()定义为一个名为dom的对象的方法(如dom.findNodes()),则回调内部将引用dom而不是预期的myapp。“

我不明白这个解释。也许作者错了?

在我看来,这种说法具有误导性。如果findeNotes()作为方法调用或作为函数调用,则与myapp.paint()方法中的this-value无关。在任何一种情况下,this-value都将引用全局对象,因为它由调用“callback(found)”的形式决定(参见http://dmitrysoshnikov.com/ecmascript/javascript-the-core/#this-value)。

任何人都可以帮我找到正确的答案吗?

2 个答案:

答案 0 :(得分:0)

作者错了。他可能在findNodes中误解paint作为解释。

  • 调用myapp.paint()将此绑定到myapp对象
  • 调用var func = myapp.paint; func()将此绑定到全局窗口对象。

更正的说明可能如下所示

  

如果你调用findNodes(myapp.paint),它将无法按预期工作,   因为this.color不会被定义。这将引用的对象   全局对象,因为 paint ()作为函数调用,而不是作为函数调用   方法。如果 paint ()被定义为名为dom的对象的方法   (比如dom。 paint ()),然后这个回调内部会引用   dom而不是预期的myapp。

答案 1 :(得分:0)

你的想法是正确的。 this内的findNodes可以是全局对象,也可以是其他对象,但this内的callback将始终是全局对象。

解决问题的一种方法是:

var findNodes = function (callback) {
    // ...
    if (typeof callback === "function") {
        callback.call(this,found); // CHANGED HERE
    }
    // ...
};

这样,findNodes的范围将传递给回调。这至少会使作者纠正。

处理回调的更常见方法是提供定义范围的可选参数:

var findNodes = function (callback, scope) {
    // ...
    if (typeof callback === "function") {
        callback.call(scope,found); // CHANGED HERE
    }
    // ...
};