`new function ()` con "f" minuscola in JavaScript


106

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

    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 "this" viene utilizzato, diventa una proprietà pubblica di someObj. 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" tramite chiusure.

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

  • strana costruzione. Elimina "nuovo"

Stiamo usando questa tecnica in produzione e sembra funzionare bene, ma sono un po 'in ansia perché non è documentata da nessuna parte. Qualcuno sa se questa è una tecnica valida?


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

1
Perché è importante per la domanda specificare "f minuscola"?
ClearCloud8

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


@Bergi ho letto i tuoi link. Non vedo motivo per screditare questo schema. È valido. È semplice. Allora cosa c'è che non va. JSLint si lamenta di tutto BTW :)
Stijn de Witt

Risposte:


64

Ho già visto quella tecnica, è valida, stai usando un'espressione di funzione come se fosse una funzione del costruttore .

Ma IMHO, puoi ottenere lo stesso con un'espressione di funzione di invocazione automatica, non vedo davvero il punto di usare l' newoperatore 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 newdell'operatore è quello di creare nuove istanze di oggetti, impostando la [[Prototype]]proprietà interna, è possibile vedere come questo viene realizzato dalla [Construct]proprietà interna.

Il codice precedente produrrà un risultato equivalente.


1
La specifica ECMAScript 262 nella sezione 13 lo spiega in modo un po 'più formale. Qualcosa di simile function foo () {}restituisce il risultato della creazione di un Functionoggetto [presumibilmente con new Function ()]. È la sintassi dello zucchero.
Clinton Pierce,

3
Penso che ti manchi un return instance;alla fine. Altrimenti, someObjsarà solo undefined. :-)
Matthew Crumley,

1
Posso suggerire che se ti interessa la modularità e l'occultamento delle informazioni, di rinunciare a questo e iniziare a utilizzare qualcosa come require.js? Sei a metà strada, perché fermarti qui? Asynchronous Module Definition (che è ciò che require.js implementa) supporta questo caso d'uso e fornisce un intero set di strumenti per gestire l'ambito, lo spazio dei nomi e la gestione delle dipendenze.
Stijn de Witt,

Si noti che le parentesi che circondano la dichiarazione della funzione non sono necessarie poiché l'istruzione è già un'espressione a causa della presenza di=
Explosion Pills

@StijndeWitt a metà strada significa che dovresti fare il doppio del lavoro per usare require.js, ma questo potrebbe essere tutto ciò di cui hai bisogno in casi semplici.
xr280xr

15

Il tuo codice è proprio simile al costrutto meno strano

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 potrebbe essere riutilizzata tramite il nuovo someObj.constructor . Qui il costruttore viene aggiunto allo spazio dei nomi in modo esplicito; 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 di nuovo prima di Foo .
J Bryan Price

@kikito cosa intendi questo non consente di riutilizzare Foo per creare un altro oggetto? var newObj = new Foo () dovrebbe creare una nuova istanza.
Bill Yang

1
@ BillYang Questo è stato 5 anni fa. Nessuna idea. Da allora non ho più toccato javascript.
kikito

12

Per chiarire alcuni aspetti e fare in modo che il JSLint di Douglas Crockford non si lamenti del tuo codice, ecco alcuni esempi di istanziazione:

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. Assomiglia a questo: new (function () {...}) (). Quindi, se omettiamo le parentesi finali come nell'esempio 2, l'espressione è ancora una chiamata di costruttore valida e ha l'aspetto dell'esempio 4.

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.