2014-12-20 25 views
8

Come si chiama una funzione pubblica da una funzione privata nel modello di modulo JavaScript?Come si chiama una funzione pubblica da una funzione privata nel modello di modulo JavaScript

Ad esempio, nel seguente codice,

var myModule = (function() { 
    var private1 = function(){ 
     // How to call public1() here? 
     // this.public1() won't work 
    } 

    return { 
     public1: function(){ /* do something */} 
    } 
})(); 

Questa domanda è stato chiesto twicebefore, con una diversa risposta accettata per ciascuno.

  1. Salvare un riferimento all'oggetto di reso prima di restituirlo, quindi utilizzare tale riferimento per accedere al metodo pubblico. Vedi answer.
  2. Salvare un riferimento al metodo pubblico nella chiusura e utilizzarlo per accedere al metodo pubblico. Vedi answer.

Mentre queste soluzioni funzionano, sono insoddisfacenti da un punto di vista OOP. Per illustrare cosa intendo, prendiamo un'implementazione concreta di un pupazzo di neve con ognuna di queste soluzioni e confrontale con un semplice oggetto letterale.

Snowman 1: Salva di riferimento per tornare all'oggetto

var snowman1 = (function(){ 
    var _sayHello = function(){ 
    console.log("Hello, my name is " + public.name()); 
    }; 

    var public = { 
    name: function(){ return "Olaf"}, 
    greet: function(){ 
     _sayHello(); 
    } 
    }; 
    return public; 
})() 

pupazzo di neve 2: Salva riferimento alla funzione pubblica

var snowman2 = (function(){ 
    var _sayHello = function(){ 
    console.log("Hello, my name is " + name()); 
    }; 
    var name = function(){ return "Olaf"}; 

    var public = { 
    name: name, 
    greet: function(){ 
     _sayHello(); 
    } 
    }; 
    return public; 
})() 

pupazzo di neve 3: letterale oggetto

var snowman3 = { 
    name: function(){ return "Olaf"}, 
    greet: function(){ 
     console.log("Hello, my name is " + this.name()); 
    } 
} 

Possiamo vedere che i tre sono identici nella funzionalità e hanno gli stessi identici metodi pubblici.

Se lanciamo un test di semplice prioritario, tuttavia

var snowman = // snowman1, snowman2, or snowman3 
snowman.name = function(){ return "Frosty";} 
snowman.greet(); // Expecting "Hello, my name is Frosty" 
       // but snowman2 says "Hello, my name is Olaf" 

vediamo che 2 # fallisce.

Se lanciamo una prova di prototipo di primaria importanza,

var snowman = {}; 
snowman.__proto__ = // snowman1, snowman2, or snowman3 
snowman.name = function(){ return "Frosty";} 
snowman.greet(); // Expecting "Hello, my name is Frosty" 
       // but #1 and #2 both reply "Hello, my name is Olaf" 

vediamo che sia # 1 e # 2 non riescono.

Questa è una situazione davvero brutta. Solo perché ho scelto di ridefinire il mio codice in un modo o nell'altro, l'utente dell'oggetto restituito deve esaminare attentamente come ho implementato tutto per capire se è in grado di sovrascrivere i metodi del mio oggetto e si aspetta che funzioni ! Mentre le opinioni qui sono diverse, la mia opinione è che il comportamento di override corretto sia quello del semplice oggetto letterale. ci

è un modo per chiamare un metodo pubblico da uno privato in modo che gli atti oggetto risultante come un oggetto letterali rispetto a sovrascrivere il comportamento:

Quindi, questa è la vera questione?

+2

Una nota importante nelle insidie ​​che si discutono: la mia comprensione del modello di modulo è che è davvero un'alternativa all'approccio del polimorfismo prototipo/OOP di JS. In quanto tale, penso che abbia senso evitare di usare i due insieme - non lo vedo come una trappola * di per sé *. – EyasSH

+0

@ EyasSH: può essere usato in questo modo, tuttavia penso che sia più un artefatto che può essere usato per una specie di eredità piuttosto che una caratteristica intenzionale. Sembra essere usato principalmente per emulare membri privati ​​(o non esponendo cose che altri non dovrebbero giocare) e anche per migliorare le prestazioni. – RobG

+1

@RobG, giusto, ma è possibile dichiarare le funzioni private in una chiusura mentre si attacca al modello di prototipo. In tal caso, l'uso di '' this this''' va bene. Il mio punto è, se si sta utilizzando il modello del modulo, penso che guardare il modulo <-> l'interazione del prototipo non è una vera ragione per non utilizzare un approccio. Potrebbe essere un buon motivo per limitarsi al prototipo se pensi che chiunque usi il tuo codice lo farà ... – EyasSH

risposta

2

È possibile utilizzare this per ottenere l'oggetto il metodo privilegiato greet è stato chiamato.

Quindi, è possibile passare tale valore al metodo privato _sayHello, ad es. utilizzando call, apply, o come argomento:

var snowman4 = (function() { 
    var _sayHello = function() { 
     console.log("Hello, my name is " + this.name); 
    }; 
    return { 
     name: "Olaf", 
     greet: function() { 
      _sayHello.call(this); 
     } 
    }; 
})(); 

Ora si può fare

var snowman = Object.create(snowman4); 
snowman.greet(); // "Hello, my name is Olaf" 
snowman.name = "Frosty"; 
snowman.greet(); // "Hello, my name is Frosty" 

E anche

snowman4.greet(); // "Hello, my name is Olaf" 
snowman4.name = "Frosty"; 
snowman4.greet(); // "Hello, my name is Frosty" 
+0

Questa risposta non sembra rispondere alla domanda su come chiamare le funzioni pubbliche all'interno delle funzioni private nel Pattern del modulo - in particolare, come dovrebbe _sayHello() chiamare name(). Il wrapping letterale dell'oggetto in un IIFE non rende neanche greet(). –

+0

@ I-LinKuo Sì, è un privilegio. Può accedere ai dati privati ​​dichiarati all'interno della funzione autoeseguibile. – Oriol

+0

Sì, era privilegiato: poteva accedere ai dati privati ​​dichiarati all'interno della funzione autoeseguita. L'ho fatto con un metodo privilegiato anziché privato per semplificare, ma è vero che non ha risposto direttamente alla domanda, quindi l'ho risolto. – Oriol

1

con il modello del modulo, si nascondono tutti i innates di un oggetto in variabili locali/funzioni e di solito impiegano quelli nelle funzioni pubbliche. Ogni volta che viene creato un nuovo oggetto con un modello di modulo, viene creato anche un nuovo insieme di funzioni esposte, con il proprio stato di ambito.

Con il modello di prototipo, si dispone dello stesso insieme di metodi disponibili per tutti gli oggetti di qualche tipo. Quello che cambia per questi metodi è l'oggetto this - in altre parole, questo è il loro stato. Ma this non è mai nascosto.

Inutile dire che è difficile mescolare quelli. Un modo possibile è estrarre i metodi usati dai privati ​​in un prototipo dell'oggetto risultante del modulo con Object.create. Ad esempio:

var guardian = function() { 
    var proto = { 
     greet: function() { 
      console.log('I am ' + this.name()); 
     }, 
     name: function() { 
      return 'Groot'; 
     } 
    }; 
    var public = Object.create(proto); 
    public.argue = function() { 
     privateGreeting(); 
    }; 

    var privateGreeting = public.greet.bind(public); 
    return public; 
}; 

var guardian1 = guardian(); 
guardian1.argue(); // I am Groot 
var guardian2 = guardian(); 
guardian2.name = function() { 
    return 'Rocket'; 
}; 
guardian2.argue(); // I am Rocket 
var guardian3 = guardian(); 
guardian3.__proto__.name = function() { 
    return 'Star-Lord'; 
}; 
guardian3.argue(); // I am Star-Lord 
Problemi correlati