3

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

实际代码超过 200 行,但我将其归结为以下内容:objA 有一个方法 (publicA),objB 希望通过回调调用该方法。使事情复杂化的细节是 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,事情确实有效。

我不能强调有更好的方法来做这件事的感觉是多么巨大。我错过了什么?

4

3 回答 3

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);现在将按预期工作。

小提琴

于 2013-07-25T11:15:06.560 回答
1

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

如何?您想在要使用callcustom 调用的回调上使用this,而不是在模块闭包上使用。它应该是

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

objB.callback(objA.publicA, objA);

我试过设置var self = this;

self变量应该在一个闭包中并指向存储方法的对象。只有this当你的模块 IEFE 会在你的模块上被调用时——它不是。或者如果它是一个构造函数 - 它不是。你可以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({});

但这很丑陋。在您的情况下, self 变量只需要指向您作为模块返回的对象文字:

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
    };
}();
于 2013-07-25T13:13:05.250 回答
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
于 2013-07-25T07:19:46.003 回答