`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.