`new function()` cu „f” minusculă în JavaScript (Programare, Javascript, Funcție, Obiect, Instanțiere)

Johnny Oshika a intrebat.

Colegul meu a folosit „new function()” cu „f” minusculă pentru a defini obiecte noi în JavaScript. Pare să funcționeze bine în toate browserele majore și pare, de asemenea, să fie destul de eficient în ascunderea variabilelor private. Iată un exemplu:

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

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

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

De îndată ce este folosit „this”, acesta devine o proprietate publică a unuiObj. Astfel, someObj.foo, someObj.get_inner() și someObj.set_inner() sunt toate disponibile în mod public. În plus, set_inner() și get_inner() sunt metode privilegiate, deci au acces la „inner” prin intermediul închiderilor.

Cu toate acestea, nu am văzut nicăieri vreo referire la această tehnică. Chiar și JSLint-ul lui Douglas Crockford se plânge de ea:

  • construcție ciudată. Ștergeți „new

Folosim această tehnică în producție și pare să funcționeze bine, dar sunt un pic neliniștit în legătură cu ea, deoarece nu este documentată nicăieri. Știe cineva dacă aceasta este o tehnică validă?

Comentarii

  • Prefer construcția dvs. în locul IIFE („Immediately-Invoked Function”). 1: Nu aveți nevoie de un obiect „instance” explicit, asta este exact ceea ce este „this” în JavaScript. 2: Nu trebuie să returnați nimic, ceea ce înseamnă că nu trebuie să vă amintiți să o faceți. Chiar și autorul răspunsului acceptat a uitat să returneze inițial obiectul instanță! De obicei, oamenii preferă să folosească un IIFE dacă urăsc noul & asta, pe bună dreptate – Dacă aveți o funcție care gestionează un eveniment DOM, this se va referi la elementul care a declanșat evenimentul, nu la obiectul dvs., dar ați putea avea doar var instance = this în schimb. –  > Por Lee Kowalkowski.
  • De ce este important pentru întrebare să se precizeze „f minusculă” ? –  > Por ClearCloud8.
  • Pentru că în Javascript există și funcția „Function” (cu F majusculă), care este diferită: Funcția este o funcție constructor care poate crea noi obiecte funcție, în timp ce function este un cuvânt cheie. –  > Por Stijn de Witt.
  • înrudite: Este corect să ne gândim la o expresie de funcție Javascript care folosește cuvântul cheie „new” ca fiind „statică”, de ce acest model? nu ar trebui să fie folosit –  > Por Bergi.
  • @Bergi Am citit linkurile tale. Nu văd niciun motiv pentru a discredita acest pattern. Este valabil. Este simplu. Deci ce nu e în regulă. JSLint se plânge de orice BTW 🙂 –  > Por Stijn de Witt.
3 răspunsuri
Christian C. Salvadó

Am mai văzut această tehnică, este valabilă, folosești o expresie de funcție ca și cum ar fi un Funcție constructoare.

Dar, IMHO, poți obține același lucru cu o expresie de funcție auto-invocată, nu prea văd rostul folosirii expresiei new în acest mod:

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;
})();

Scopul new este de a crea noi instanțe de obiect, stabilind astfel [[Prototype]] proprietate internă, puteți vedea cum se realizează acest lucru prin intermediul funcției [Construct] proprietatea internă.

Codul de mai sus va produce un rezultat echivalent.

Comentarii

  • Specificația ECMAScript 262 din secțiunea 13 explică acest lucru puțin mai formal. Ceva de genul function foo () {} returnează rezultatul creării unei proprietăți Function obiect [probabil cu new Function ()]. Este un zahăr sintactic. –  > Por Clinton Pierce.
  • Cred că vă lipsește un return instance; la sfârșit. Altfel, someObj va fi doar undefined. 🙂 –  > Por Matthew Crumley.
  • Pot să vă sugerez că, dacă vă pasă de modularitate și de ascunderea informațiilor, să renunțați la acest lucru și să începeți să folosiți ceva de genul require.js? Sunteți la jumătatea drumului, de ce să vă opriți aici? Asynchronous Module Definition (care este ceea ce implementează require.js) suportă acest caz de utilizare și vă oferă un întreg set de instrumente pentru a vă ocupa de definirea domeniului de aplicare, namespacing și gestionarea dependențelor. –  > Por Stijn de Witt.
  • Rețineți că parantezele care înconjoară declarația funcției sunt inutile, deoarece declarația este deja o expresie datorită prezenței lui = –  > Por Pastile de explozie.
  • @StijndeWitt la jumătatea drumului înseamnă că ar trebui să faceți de două ori mai multă muncă pentru a folosi require.js, dar s-ar putea ca acest lucru să fie tot ce aveți nevoie în cazuri simple. –  > Por xr280xr.
kennytm

Codul dvs. este doar similar cu construcția mai puțin ciudată

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

    ...
};
var someObj = new Foo;

Comentarii

  • Nu este doar similar, ci face exact același lucru… cu singura excepție că nu vor putea refolosi Foo pentru a crea un alt obiect. –  > Por kikito.
  • Versiunea lui OP ar putea fi refolosită prin new someObj.constructor. Aici, constructorul este adăugat în mod explicit la spațiul de nume; stilul corect depinde de scopul urmărit al funcției. De asemenea, acest stil – deși este cu siguranță standardul – permite cuiva să populeze spațiul de nume global dacă uită new înainte de Foo. –  > Por J Bryan Price.
  • @kikito ce vrei să spui că acest lucru nu permite reutilizarea Foo pentru a crea un alt obiect? var newObj = new Foo() ar trebui să creeze o nouă instanță. –  > Por Bill Yang.
  • @BillYang Asta a fost acum 5 ani. Habar nu am. Nu m-am mai atins de javascript de atunci. –  > Por kikito.
DUzun

Pentru a clarifica unele aspecte și pentru a face ca JSLint-ul lui Douglas Crockford să nu se plângă de codul tău, iată câteva exemple de instanțiere:

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

În exemplul 3. expresia din (….) ca valoare este o funcție/constructor. Arată astfel: new (function (){…})(). Deci, dacă omitem parantezele finale ca în exemplul 2, expresia este tot un apel de constructor valid și arată ca în exemplul 4.

JSLint al lui Douglas Crockford „crede” că ați vrut să atribuiți funcția la someObj, nu la instanța acestuia. Și, la urma urmei, este doar un avertisment, nu o eroare.