2010-02-16 18 views
104

Il mio collega ha utilizzato "nuova funzione()" con una minuscola "f" per definire nuovi oggetti in JavaScript. Sembra funzionare bene in tutti i principali browser e sembra anche essere abbastanza efficace nel nascondere variabili private. Ecco un esempio:`nuova funzione()` con minuscolo "f" in JavaScript

var someObj = new function() { 
     var inner = 'some value'; 
     this.foo = 'blah'; 

     this.get_inner = function() { 
      return inner; 
     }; 

     this.set_inner = function (s) { 
      inner = s; 
     }; 
    }; 

Non appena "questo" viene utilizzato, diventa una proprietà pubblica di alcuniObj. Quindi someObj.foo, someObj.get_inner() e someObj.set_inner() sono tutti disponibili pubblicamente. Inoltre, set_inner() e get_inner() sono metodi privilegiati, quindi hanno accesso a "inner" attraverso le chiusure.

Tuttavia, non ho visto alcun riferimento a questa tecnica da nessuna parte. JSLint di Anche Douglas Crockford lamenta:

  • costruzione strano. Elimina 'nuovo'

Stiamo utilizzando questa tecnica nella produzione e sembra funzionare bene, ma io sono un po 'ansioso su di esso perché non è documentato da nessuna parte. Qualcuno sa se questa è una tecnica valida?

+5

Preferisco il tuo costrutto rispetto all'IIFE ('Funzione richiamata immediatamente'). 1: Non hai bisogno di un esplicito oggetto "istanza", questo è esattamente ciò che "questo" è in JavaScript. 2: Non è necessario restituire nulla, il che significa che non è necessario ricordarsi di farlo. Persino l'autore della risposta accettata ha dimenticato di restituire inizialmente l'oggetto istanza! Le persone di solito preferiscono usare un IIFE se odiano di nuovo e questo, con buone ragioni - Se hai una funzione che gestisce un evento DOM, questo si riferirà all'elemento che ha generato l'evento, non al tuo oggetto, ma potresti semplicemente avere 'var instance = this' invece. –

+1

Perché è importante per la domanda specificare "minuscolo f"? – ClearCloud8

+7

Perché in Javascript esiste anche la funzione 'Funzione' (con F maiuscola), che è diversa: __Function__ è una funzione di costruzione che può creare nuovi oggetti funzione, mentre __function__ è una parola chiave. –

risposta

63

Ho visto prima questa tecnica, è valida, si sta usando un'espressione di funzione come se fosse un Constructor Function.

Ma secondo me, è possibile ottenere lo stesso con un'espressione funzione di auto-invocazione, io non vedo proprio il punto di usare l'operatore new in questo modo:

var someObj = (function() { 
    var instance = {}, 
     inner = 'some value'; 

    instance.foo = 'blah'; 

    instance.get_inner = function() { 
     return inner; 
    }; 

    instance.set_inner = function (s) { 
     inner = s; 
    }; 

    return instance; 
})(); 

Lo scopo dell'operatore new è quello di creare nuove istanze di oggetti, impostando la proprietà interna [[Prototype]], è possibile vedere come questo è fatto dalla proprietà interna [Construct].

Il codice sopra riportato produce un risultato equivalente.

+1

La specifica ECMAScript 262 nella Sezione 13 lo spiega un po 'più formalmente. Qualcosa come 'function foo() {}' restituisce il risultato della creazione di un oggetto 'Function' [presumibilmente con new Function()]. È zucchero sintassi. –

+3

Penso che manchi un 'return instance;' alla fine. Altrimenti, 'someObj' sarà semplicemente' indefinito'.:-) –

+0

@Matthew: Sì, ho perso l'istruzione 'return', grazie. – CMS

15

Il codice è solo simile a quello meno strano costrutto

function Foo() { 
    var inner = 'some value'; 
    this.foo = 'blah'; 

    ... 
}; 
var someObj = new Foo; 
+9

Non è solo simile, fa esattamente la stessa cosa ... con la sola eccezione che non saranno in grado di riutilizzare Foo per creare un altro oggetto. – kikito

+3

La versione dell'OP può essere riutilizzata tramite ** new someObj.constructor **. Qui il costruttore viene aggiunto esplicitamente al namespace; lo stile giusto dipende dallo scopo previsto della funzione. Inoltre, questo stile - sebbene certamente lo standard - consente a qualcuno di popolare lo spazio dei nomi globale se dimentica ** nuovo ** prima di ** Foo **. –

+0

@kikito cosa intendi per non consentire il riutilizzo di Foo per la creazione di un altro oggetto? var newObj = new Foo() dovrebbe creare una nuova istanza. –

12

Per chiarire alcuni aspetti e fare JSLint di Douglas Crockford di non lamentarsi il codice ecco alcuni esempi di esemplificazione:

1. o = new Object(); // normal call of a constructor 

2. o = new Object; // accepted call of a constructor 

3. var someObj = new (function() { 
    var inner = 'some value'; 
    this.foo = 'blah'; 

    this.get_inner = function() { 
     return inner; 
    }; 

    this.set_inner = function (s) { 
     inner = s; 
    }; 
})(); // normal call of a constructor 

4. var someObj = new (function() { 
    var inner = 'some value'; 
    this.foo = 'blah'; 

    this.get_inner = function() { 
     return inner; 
    }; 

    this.set_inner = function (s) { 
     inner = s; 
    }; 
}); // accepted call of a constructor 

Nell'esempio 3. espressione in (...) come valore è una funzione/costruttore. È il seguente: new (function() {...})(). Quindi, se omettiamo le parentesi quadre come nell'esempio 2, l'espressione è ancora una chiamata di costruttore valida e assomiglia ad esempio 4.

JSLint di Douglas Crockford "pensa" che si desidera assegnare la funzione a someObj, non la sua istanza. E dopotutto è solo un avvertimento, non un errore.

Problemi correlati