在揭示模块模式中访问私有方法的最佳实践

Best Practices for accessing private methods in the revealing module pattern

我看到的几乎每个揭示模块模式教程都会显示一个 public 方法访问一个私有方法 without 使用 "method.call(this,...)".

这似乎可以很好地完成工作,但如果您在私有方法中执行 trace(this),它将显示 "Window"。这感觉像是一个潜在的陷阱。

我应该使用 call(或 apply),还是会引入不必要的复杂性?

笨蛋:https://plnkr.co/edit/hc3ZPJyeHcT9bLbLaLpX?p=preview

编辑:我的想法是,通过使用 "call",它以某种方式使它成为 "safer",因为上下文是 api 对象而不是全局命名空间。

var Module = (function () {

    var _privateVar = "PRIVATE!";

    var api = {
        publicMethod: publicMethod
    }

    return api;

    function publicMethod() {
        privateMethod();
        privateMethod.call(this);
    };

    function privateMethod(message) {
        console.log(_privateVar, this);
    };


})();

Module.publicMethod();

你的 Module 永远不会在它自己的上下文中,因此调用它的静态函数将导致 this 成为全局对象。

--

您可以尝试 来解决这个问题(通过创建 "newable" 对象):

const Module = (function () {
    var _privateVar = "PRIVATE!";

    const Api = function () {

    };

    function publicMethod() {
        privateMethod();
        privateMethod.call(this);
    };

    function privateMethod(message) {
        console.log(_privateVar, this);
    };

    Api.protoype.publicMethod = publicMethod;

    return Api;
});

const module = new Module();

console.log(module.publicMethod());

没有最佳实践。两者

function privateFunction(self, message) { // also popular: `that`
    // do something with `self`
}
…
privateFunction(this, …);

function privateMethod(message) {
    // do something with `this`
}
…
privateMethod.call(this, …);

很好。只需坚持一种风格并保持代码库一致。然而,第一个可能更受欢迎,因为许多私有函数实际上是静态的,不需要实例来处理,所以它简化了使用实例的显式参数的事情(而不是 assuming/hoping 函数是使用预期的 this 值调用)。

过去几天我一直在为这个问题苦苦挣扎,很高兴遇到这个问题。然而,经过一些试验,none 的答案似乎至少在一种情况下令人满意:在 public 和私有函数之间传递数据。

下面是三个示例,使用 'call'、'bind' 和普通调用。绑定似乎是将私有方法保留在本地范围内的唯一方法,并且还允许私有方法和 public 方法之间进行数据交换。将上下文传递给私有方法的另一个建议仍然会使私有方法在模块外部执行(如果我理解正确的话)。

有趣的是,使用普通调用(with/without 严格模式)允许数据交换,即使私有方法的上下文是 'undefined'/'window'.

使用'bind':

"use strict"; 
var home = (function(){

  var bob = function(){
    console.log("Bob's scope: " + Object.keys(this));  // "Bob's scope: init"
    var bob_says = "Hello";
    var fBound = alice.bind(this);
    var alice_reply = fBound(bob_says);
    console.log("Alice answered: " + alice_reply);     // "Alice answered: Hello Bob"
  };

  var alice = function(bob_greeting){
    var scope = this ? Object.keys(this) : this;
    console.log("Alice's scope: " + scope);            // "Alice's scope: init"
    console.log("Bob said: " + bob_greeting);          // "Bob said: Hello"
    return bob_greeting + " Bob"; 
  };

  return { init : bob };
})();

home.init();

使用'call':

"use strict"; 
var home = (function(){

  var bob = function(){
    console.log("Bob's scope: " + Object.keys(this));  // "Bob's scope: init"
    var bob_says = "Hello"; 
    var alice_reply = alice.call(this, bob_says);
    console.log("Alice answered: " + alice_reply);     // "Alice answered: undefined Bob"
  };

  var alice = function(self, bob_greeting){
    var scope = this ? Object.keys(this) : this;
    console.log("Alice's scope: " + scope);            // "Alice's scope: init"
    console.log("Bob said: " + bob_greeting);          // "Bob said: undefined"
    return bob_greeting + " Bob"; 
  };

  return { init : bob };
})();

home.init();

没有调用或绑定:

"use strict";
var home = (function(){

  var bob = function(){
    console.log("Bob's scope: " + Object.keys(this));  // "Bob's scope: init"
    var bob_says = "Hello"; 
    var alice_reply = alice(bob_says);
    console.log("Alice answered: " + alice_reply);     // "Alice answered: Hello Bob"
  };

  var alice = function(bob_greeting){
    var scope = this ? Object.keys(this) : this;
    console.log("Alice's scope: " + scope);            // "Alice's scope: undefined"
    console.log("Bob said: " + bob_greeting);          // "Bob said: Hello"
    return bob_greeting + " Bob"; 
  };

  return { init : bob };
})();

home.init();

更新和可能的答案。 我很好奇,当 Alice 在没有 'call' 或 'bind' 的情况下被调用并且她的上下文未定义(或 window)时,她是否可以访问 [=37= 中的私有变量]?是的,所以我对 OP(和我自己)的初步回答是正常调用私有函数:没有 'bind',没有 'call' 并且不需要传递上下文,而是 "use strict" 如果它让您看到 window 上下文在 运行 私有函数时弹出。似乎在 'window' 中没有创建新的 属性,如果 window 有一个与私有函数同名的对象(无论是否打开严格模式),则不会发生冲突离开)。如果有问题,我还没有遇到。

"use strict";

var alice = "Hi, I'm global's Alice"; 

var home = (function(){

  var bob = function(){
    console.log("Bob's scope: " + Object.keys(this)); // "Bob's scope: init" 
    var bob_says = "Hello";
    var alice_reply = alice(bob_says);
    console.log("Alice answered: " + alice_reply);    // "Alice answered: Hello Bob. I'm in the garage."
  };

  var alice_location = "in the garage.";

  var alice = function(bob_greeting){
    var scope = this ? Object.keys(this) : this;
    console.log("Alice's scope: " + scope);           // "Alice's scope: undefined"
    console.log("Bob said: " + bob_greeting);         // "Bob said: Hello"
    return bob_greeting + " Bob. I'm " + alice_location; 
  };

  return { init : bob };

})();

home.init();

console.log(alice);