2012-02-16 14 views
10

ho trovato qualcosa di molto strano oggi: se si crea oggetti con una funzione di costruzione e la parola chiave new, ma return una funzione dal costruttore, si comporta in questo modo:Usando 'ritorno' per la creazione di oggetti con 'nuovo'

  1. Il "oggetto" appena creato è invece una funzione.
  2. Questa nuova funzione può essere invocata come normale, però ...
  3. Se si mantiene un riferimento alla this nella funzione di costruzione, this riferimento a un oggetto che è stato correttamente creato dal costruttore. È quello che ti aspettavi di essere restituito da new.

Ecco un esempio:

function Constructor() { 
    var self = this; 

    this.name = 'instance'; 
    return function() { 
    return self; 
    } 
} 

Quindi, se avete istanziato in questo modo: var instance = new Constructor() Di seguito si tradurrebbe:

typeof instance //returns "function" 
typeof instance() //returns "object" 
instance()   //returns { name: 'instance' } 

Quindi credo Ho tre domande:

  1. È legale e funziona? k cross-browser? È davvero fantastico e penso che possa essere usato in molti modi, ma questo comportamento è affidabile?
  2. Cosa succede in background che causa questo comportamento?
  3. (forse ha risposto con 2, ma ...) Il nuovo oggetto (quello referenziato con 'this') all'interno della nuova istanza, in modo che sia tutto autonomo e che venga corretto correttamente dal garbage collector?
+0

È sbagliato restituire qualcosa da un costruttore, l'ultima volta che l'ho sentito. –

risposta

7
  1. Sì, mentre un costruttore di default restituisce il nuovo oggetto in costruzione (che fa riferimento this), è possibile ignorare che il valore di ritorno purché si restituire un oggetto. Poiché una funzione è un oggetto, puoi restituirla come nel tuo esempio. L'oggetto appena creato è non una funzione stessa, ma la funzione restituita fa riferimento all'oggetto appena creato nel suo ambito variabile.

  2. Vedi # 1

  3. Questo perché una funzione crea una chiusura, così continua fare riferimento alla variabile self, che avviene per fare riferimento all'oggetto effettivo in costruzione. Quindi non direi che è "dentro" qualsiasi cosa, ma piuttosto è semplicemente parte dell'ambito variabile della funzione.

La cosa da capire è che la funzione non è diversa da qualsiasi altra funzione. Proprio come se avessi invece restituito una matrice, avresti semplicemente una matrice regolare, che potrebbe fare riferimento al nuovo oggetto.

function Constructor() { 

    this.name = 'instance'; 
    return [ this ]; // Instead return an Array that references the new object 
} 
+0

I see! Quindi la variabile "istanza" nel mio esempio è una * chiusura *, non una funzione normale? E quella chiusura contiene sia la funzione restituita che l'oggetto istanziato, a cui si può accedere con "questo"? –

+2

@KevinMcTigue: Bene, tutte le funzioni sono chiusure. È semplicemente parte dell'implementazione interna delle funzioni in JavaScript. Ciò che rende una funzione una chiusura è che ha un riferimento permanente allo scope della variabile originale in cui è stato creato. Quindi stai solo restituendo una semplice vecchia funzione, che si comporta in modo corretto come qualsiasi altra funzione, in quanto non perde di vista il suo ambito variabile * (che include la variabile 'self', che fa riferimento al tuo nuovo oggetto) *. –

2

Bene, questa è una domanda davvero buona e, come avrete intuito, non è stata una risposta facile.

Per dirla in parole semplici:
1) Sì e Sì; questa è una delle straordinarie funzionalità che non si trovano nei linguaggi di programmazione "tradizionali".
2) Si prega di leggere su chiusure (link qui sotto)
3) Sì (leggi tutto)

Si dovrebbe leggere di più su Javascript Closures: http://jibbering.com/faq/notes/closures/
http://www.javascriptkit.com/javatutors/closures.shtml (qui avete ottenuto alcuni buoni esempi di lavoro)

e, più in particolare, il modello di ereditarietà Parassita:
http://blog.higher-order.net/2008/02/21/javascript-parasitic-inheritance-power-constructors-and-instanceof/

Spero che questo aiuta

+0

Grazie per i collegamenti. Il secondo è molto interessante. Oggi ho imparato un nuovo termine: Power Constructor –

1

questo è quello che si chiama un closure

ciò che fa è creare un ambiente di codice autonomo (comunemente noto come un oggetto)

typeof instance //returns "function" - since it's not "fired" or called. just returns the function declaration (correct me if i'm wrong) 
typeof instance() //returns "object" - it returns an object since you called it 
instance()   //returns an object also - you called it, but you didn't store it 

un esempio di un oggetto costruito utilizzando una chiusura:

function Constructor() { 
    var privateProperty = 'private'; 
    var privateMethod = function(){ 
     alert('called from public method'); 
    }; 

    //return only what's to be seen in public 
    return { 
     publicProperty: 'im public', 
     publicMethod: function(){ 
      alert('called from public method'); 
     } 
     getter: privateMethod //assign to call the private method 
    } 
} 

var myObj = Constructor(); 
var pubProp = myObj.publicProperty; // pubProp = 'im public' 
myObj.publicMethod()    //alert: 'called from public method'; 
myObj.getter()      //alert: 'called from public method'; 

//cannot access since "private": 
myObj.privateProperty 
myObj.privateMethod 
+1

_ "ciò che fa è creare un ambiente di codice autonomo (comunemente noto come oggetto)" _ - Comunemente noto come "chiusura". Non è un "oggetto", almeno non nel senso di essere un oggetto JS. Inoltre, se la tua funzione restituisce esplicitamente un oggetto, non è una buona pratica chiamarlo con 'new' perché ciò è fuorviante - se usi' new' ti aspetteresti che il risultato fosse un'istanza di 'Costruttore'. – nnnnnn

+0

Secondo la pagina MDN sulle chiusure: * "Una chiusura è un tipo speciale di oggetto che combina due cose: una funzione e l'ambiente in cui è stata creata quella funzione." * –

+1

@nnnnnn ho appena spiegato in termini semplici. sebbene non sia un oggetto, è comune utilizzarlo per emulare un oggetto (con proprietà private e pubbliche). per quanto riguarda il 'nuovo' ... non lo sapevo. – Joseph

Problemi correlati