JS Module Pattern的公共方法作为回调牺牲品。 (这个问题)

时间:2013-07-25 05:38:24

标签: javascript callback closures this module-pattern

我花了大部分时间阅读有关模块模式及其“此”范围的内容。最终我找到了解决问题的方法,尽管有一种更好的做事方式。

实际代码大于200行,但我将其归结为以下内容: objA有一个objB希望通过回调调用的方法(publicA)。使事情变得复杂的细节是publicA需要来自publicA_helper的帮助来完成它的工作。 (http://jsfiddle.net/qwNb6/2/

var objA = function () {
    var privateA = "found";
    return {
        publicA: function () {
            console.log("privateA is " + this.publicA_helper());
        },
        publicA_helper: function () {
            return privateA;
        }
    };
}();

var objB = function () {
    return {
        callback: function (callback) {
            callback();
        }
    }
}();

objA.publicA(); // privateA is found
objB.callback(objA.publicA); // TypeError: Object [object global]

足够公平 - 我已经意识到调用者的上下文会影响'this'的值。所以我添加了一些措施来保留objA中的'this',其中似乎没有效果。我试过了 var objA = (){}.call({}),设置var self = this;(相应地调用self.publicA_helper())。没有运气。

最后,我添加了一个私有变量var self;以及一个公共方法:

init: function() {self = this;},

...并确保在将objA.init();传递给objA.publicA之前致电objB.callback,事情确实有效。

我无法强调这种感觉有一种更好的方式。我错过了什么?

3 个答案:

答案 0 :(得分:3)

通用解决方案非常简单。

将所有模块的方法写为私有,然后公开那些需要公开的方法。

我用这种方式编写所有模块:

var objA = function () {
    var privateA = "found";
    var A = function () {
        console.log("privateA is " + A_helper());
    },
    var A_helper = function () {
        return privateA;
    }
    return {
        publicA: A
        //A_helper need not be exposed
    };
}();

因此,所有方法都在相同的范围内,每个方法都可以直接访问同一模块中的所有其他方法,并且避免使用模糊的this前缀。

objB.callback(objA.publicA);现在可以按预期工作了。

参见 fiddle

答案 1 :(得分:1)

  

我尝试了var objA = (){}.call({})的东西,

如何?您希望在要使用自定义call调用的回调上使用this,而不是在模块闭包上。它应该是

var objB = {
    callback: function (callback, context) {
        callback.call(context);
    }
};

objB.callback(objA.publicA, objA);
  

我尝试过设置var self = this;

self变量应该在闭包中并指向存储方法的对象。当您的模块上调用模块IEFE时,这只是this - 事实并非如此。或者,如果它是一个构造函数 - 它不是。您可以使用call进行更改,如上所述:

var objA = function () {
    var privateA = "found",
        self = this;
    this.publicA = function () {
        console.log("privateA is " + self.publicA_helper());
    };
    this.publicA_helper = function () {
        return privateA;
    };
    return this;
}.call({});

但那很难看。在您的情况下,自变量只需要指向您作为模块返回的对象文字:

var objA = function () {
    var privateA = "found",
        self;
    return self = {
        publicA: function () {
            console.log("privateA is " + self.publicA_helper());
        },
        publicA_helper: function () {
            return privateA;
        }
    };
}();

顺便说一句,既然你正在创建一个单例,你不需要一个明确的self,你可以只引用包含你的模块的变量(只要它不会改变):

var objA = function () {
    var privateA = "found";
    return {
        publicA: function () {
            console.log("privateA is " + objA.publicA_helper());
        },
        publicA_helper: function () {
            return privateA;
        }
    };
}();

另一种方法是简单地将所有函数设为私有,然后公开其中的一些 - 通过引用它们本地范围,你将没有麻烦。

var objA = function () {
    var privateA = "found";
    function publicA() {
        console.log("privateA is " + helper());
    }
    function helper() {
        return privateA;
    }
    return self = {
        publicA: publicA,
        publicA_helper: helper // remove that line if you don't need to expose it
    };
}();

答案 2 :(得分:0)

原因是在调用回调时上下文会发生变化。不是通用的解决方案,但通过在调用回调时指定上下文来显示代码的工作原理。

var objA = function () {
  var privateA = "found";
  return {
    publicA: function () {
        console.log("privateA is " + this.publicA_helper());
    },
    publicA_helper: function () {
        return privateA;
    }
  };
}();

var objB = function () {
    return {
        callback: function (callback) {
          callback.call(objA);
        }
   }
}();

objA.publicA(); // privateA is found
objB.callback(objA.publicA); // privateA is found