2016-11-14 2 views
0

Fast jede aufschlussreiche Modulmuster-Anleitung, die ich gesehen habe, zeigt eine öffentliche Methode ohne mit "Methode. Aufruf (diese, ...) ".Best Practices für den Zugriff auf private Methoden im Muster der enthüllenden Module

Dies scheint die Arbeit in Ordnung zu bringen, aber wenn Sie eine Spur (this) in der privaten Methode machen, wird es "Window" zeigen. Das fühlt sich an wie ein potenzieller Gotcha.

Sollte ich call (oder apply) verwenden, oder würde dies unnötige Komplexität einführen?

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

EDIT: Mein Denken ist, dass „Call“ unter Verwendung macht es irgendwie „sicherer“, da der Kontext das Objekt api ist eher als die globale Namespace.

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(); 

Antwort

0

Es gibt keine beste Praxis. Sowohl

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

und

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

sind in Ordnung. Bleiben Sie einfach bei einem Stil und halten Sie Ihre Codebasis konsistent. Der erste ist jedoch möglicherweise populärer, weil viele private Funktionen tatsächlich statisch sind und keine Instanz zum Arbeiten benötigen. Daher vereinfacht es die Verwendung von expliziten Parametern für die Instanz (anstatt anzunehmen/zu hoffen, dass die Funktion aufgerufen wird) der erwartete this Wert).

+0

Explizit erscheint am besten. Allerdings habe ich einen kleinen Vorteil bei der Verwendung von Anrufen festgestellt - wenn Sie einen Debugger verwenden, können Sie Getter direkt über das Objekt "this" direkt erreichen – Skyler

-1

Ihre Module ist nie in seinem eigenen Kontext, dafür eine statische Funktion nennt es führt in this das globale Objekt zu sein.

-

Sie können versuchen, das zu beheben, wie so (durch ein "newable" Objekt erstellen):

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()); 
+0

Sie sagen "versuchen", weil es nicht wirklich ratsam ist (um ein aufschlussreiches Modulmuster "neu aufzurichten")? Scheint umständlich das zu tun. – Skyler

+0

Sie sollten eine Funktion, die kein Konstruktor ist, nicht mit 'new' aufrufen. Ihr 'Modul' ist eine Factory-Funktion, die ein Objekt zurückgibt, so dass die Verwendung von' new' sinnlos ist. Es ändert den Kontext von 'privateMethod' sowieso nicht. – Bergi

+0

Es gibt eine Funktion und kein Objekt zurück – Neal

0

Ich habe in den letzten paar Tagen damit zu kämpfen, und war glücklich, auf diese Frage zu kommen. Nach einigen Experimenten scheint jedoch keine der Antworten für mindestens einen Fall zufriedenstellend zu sein: die Weitergabe von Daten zwischen der öffentlichen und der privaten Funktion.

Im Folgenden finden Sie drei Beispiele, die 'call', 'bind' und einen einfachen Aufruf verwenden. Die Bindung scheint die einzige Möglichkeit zu sein, die private Methode im lokalen Bereich zu halten und auch den Datenaustausch zwischen privaten und öffentlichen Methoden zu ermöglichen. Der andere Vorschlag, den Kontext an die private Methode zu übergeben, würde die private Methode immer noch außerhalb des Moduls ausführen lassen (wenn ich es richtig verstanden habe).

Interessanterweise erlaubt die Verwendung eines einfachen Aufrufs (mit/ohne striktem Modus) den Datenaustausch, selbst wenn der Kontext der privaten Methode 'undefiniert'/'Fenster' ist.

Mit '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(); 

Mit 'Anruf':

"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(); 

Ohne Anruf oder binden:

"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(); 

Update und mögliche Antwort. Ich war neugierig, ob, wenn Alice ohne 'Call' oder 'Bind' aufgerufen wird und ihr Kontext nicht definiert ist (oder Fenster), hat sie Zugriff auf private Variablen in 'Home'? Ja, also ist meine vorläufige Antwort auf das OP (und ich), die private Funktion einfach normal zu nennen: kein 'bind', kein 'call' und keine Notwendigkeit, den Kontext zu überschreiten, sondern 'strict', wenn es Sie stört um zu sehen, dass der Fensterkontext beim Ausführen der privaten Funktion auftaucht. Es scheint, dass keine neue Eigenschaft im "Fenster" erstellt wird, und es gibt keine Konflikte, wenn das Fenster ein Objekt mit demselben Namen wie die private Funktion hat (ob der strikte Modus aktiviert oder deaktiviert ist). Wenn es Gotchas gibt, bin ich ihnen noch nicht begegnet.

"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);