javascript - Care este diferența dintre `new Object()` și notația literală a unui obiect?


Care este diferența dintre această sintaxă bazată pe constructor pentru crearea unui obiect:

person = new Object()

...și această sintaxă literală:

person = {
    property1 : "Hello"
};

Se pare că ambele fac același lucru, deși JSLint preferă să folosești notația literală a obiectelor.

Care este mai bun și de ce?

Răspuns #1

Nu există nicio diferență pentru un obiect simplu fără metode, așa cum este în exemplul tău. Cu toate acestea, există o diferență mare atunci când începi să adaugi metode obiectului tău.

Mod literal:

function Obj( prop ) { 
    return { 
        p : prop, 
        sayHello : function(){ alert(this.p); }, 
    }; 
} 

Mod prototip:

function Obj( prop ) { 
    this.p = prop; 
} 
Obj.prototype.sayHello = function(){alert(this.p);}; 

Ambele moduri permit crearea de instanțe ale Obj astfel:

var foo = new Obj( "hello" ); 

Totuși, cu metoda literală, porți o copie a metodei sayHello în fiecare instanță a obiectelor tale. În schimb, cu metoda prototype, metoda este definită în prototipul obiectului și este partajată între toate instanțele obiectului. Dacă ai multe obiecte sau multe metode, metoda literală poate duce la un consum destul de mare de memorie.

Răspunsul #2

Ambele fac același lucru (exceptând cazul în care cineva a făcut ceva neobișnuit), altfel al doilea creează un obiect și adaugă o proprietate la el. Dar notația literală ocupă mai puțin spațiu în codul sursă. Este clar recunoscut ceea ce se întâmplă, așa că folosind new Object(), practic doar tastezi mai mult și (în teorie, dacă nu este optimizat de motorul JavaScript) faci un apel de funcție inutil.

Aceștia

person = new Object() /*You should put a semicolon here too.  
It's not required, but it is good practice.*/ 
-or-

person = {
    property1 : "Hello"
};

Tehnic, nu fac același lucru. Primul doar creează un obiect. Al doilea creează unul și îi atribuie o proprietate. Pentru ca primul să fie la fel, ai nevoie apoi de un al doilea pas pentru a crea și a atribui proprietatea.

„Ceva neobișnuit” pe care cineva l-ar putea face ar fi să umbrească sau să atribuie globalul implicit Object:

// Don't do this
Object = 23;

În acel caz foarte neobișnuit, new Object va eșua, dar {} va funcționa.

În practică, nu există niciodată un motiv să folosiți new Object în loc de {} (cu excepția cazului în care ați făcut acel lucru foarte neobișnuit).

Răspunsul #3

În JavaScript, putem declara un obiect nou gol în două moduri:

var obj1 = new Object();  
var obj2 = {};  

Nu am găsit nimic care să sugereze că există vreo diferență semnificativă între aceste două în ceea ce privește modul în care funcționează în culise (vă rog să mă corectați dacă greșesc - mi-ar plăcea să știu). Cu toate acestea, a doua metodă (folosind notația literală a obiectului) oferă câteva avantaje.

  1. Este mai scurt (10 caractere, mai exact)
  2. Este mai ușor și mai structurat să creezi obiecte pe loc
  3. Nu contează dacă vreun clovn a suprascris din greșeală Object

Luați în considerare un obiect nou care conține membrii Name și TelNo. Folosind convenția new Object(), îl putem crea astfel:

var obj1 = new Object();  
obj1.Name = "A Person";  
obj1.TelNo = "12345"; 

Caracteristica Expando Properties a JavaScript ne permite să creăm membri noi în acest mod instantaneu și realizăm ceea ce intenționam. Totuși, acest mod nu este foarte structurat sau încapsulat. Ce s-ar întâmpla dacă am dori să specificăm membrii la crearea obiectului, fără a fi nevoie să ne bazăm pe proprietăți expando și atribuiri după crearea obiectului?

Aici este locul unde notația literală a obiectului poate ajuta:

var obj1 = { Name: "A Person", TelNo: "12345" };  

Aici am obținut același efect într-o singură linie de cod și cu semnificativ mai puține caractere.

O discuție suplimentară despre metodele de construire a obiectelor menționate mai sus poate fi găsită la: JavaScript și Programarea Orientată pe Obiecte (OOP).

Și, în sfârșit, ce este cu idiotul care a suprascris Object? Ai crezut că nu este posibil? Ei bine, acest JSFiddle demonstrează contrariul. Folosirea notației literale de obiect ne împiedică să cădem pradă acestei prostii.

(De pe http://www.jameswiseman.com/blog/2011/01/19/jslint-messages-use-the-object-literal-notation/)

Răspunsul #4

Pe calculatorul meu, folosind Node.js, am rulat următoarele:

console.log('Testing Array:');
console.time('using[]');
for(var i=0; i<200000000; i++){var arr = []};
console.timeEnd('using[]');

console.time('using new');
for(var i=0; i<200000000; i++){var arr = new Array};
console.timeEnd('using new');

console.log('Testing Object:');

console.time('using{}');
for(var i=0; i<200000000; i++){var obj = {}};
console.timeEnd('using{}');

console.time('using new');
for(var i=0; i<200000000; i++){var obj = new Object};
console.timeEnd('using new');

Notă, aceasta este o extensie a ceea ce se găsește aici: De ce arr=[] este mai rapid decât arr=new Array?

rezultatul meu a fost următorul:

Testing Array:
using[]: 1091ms
using new: 2286ms
Testing Object:
using{}: 870ms
using new: 5637ms

deci în mod clar {} și [] sunt mai rapide decât folosirea lui new pentru a crea obiecte/tablouri goale.

Răspunsul #5

Toată lumea de aici vorbește despre asemănările celor doi. Eu o să subliniez diferențele.

  1. Folosind new Object() vă permite să treceți un alt obiect. Rezultatul evident este că obiectul creat recent va fi setat la aceeași referință. Iată un exemplu de cod:

    var obj1 = new Object();
    obj1.a = 1;
    var obj2 = new Object(obj1);
    obj2.a // 1
    
  2. Utilizarea nu este limitată la obiecte așa cum se întâmplă în obiectele OOP. Alte tipuri pot fi transmise și ele. Funcția va seta tipul corespunzător. De exemplu, dacă îi transmitem un număr întreg 1, va fi creat pentru noi un obiect de tip număr.

    var obj = new Object(1);
    typeof obj // "number"
    
  3. Obiectul creat folosind metoda de mai sus (new Object(1)) ar fi convertit în tip obiect dacă i se adaugă o proprietate.

    var obj = new Object(1);
    typeof obj // "number"
    obj.a = 2;
    typeof obj // "object"
    
  4. Dacă obiectul este o copie a unei clase copil a obiectului, am putea adăuga proprietatea fără conversia tipului.

    var obj = new Object("foo");
    typeof obj // "object"
    obj === "foo" // true
    obj.a = 1;
    obj === "foo" // true
    obj.a // 1
    var str = "foo";
    str.a = 1;
    str.a // undefined
    

Răspunsul #6

De fapt, există mai multe moduri de a crea obiecte în JavaScript. Când vrei doar să creezi un obiect, nu există niciun beneficiu în a crea obiecte „bazate pe constructor” folosind operatorul „new”. Este același lucru ca și cum ai crea un obiect folosind sintaxa „literala a obiectului”. Dar obiectele „bazate pe constructor” create cu operatorul „new” devin extrem de utile atunci când te gândești la „moștenirea prototipală”. Nu poți menține lanțul de moștenire cu obiecte create folosind sintaxa literală. Dar poți crea o funcție constructor, atașa proprietăți și metode la prototipul său. Apoi, dacă atribui această funcție constructor oricărei variabile folosind operatorul "new", va returna un obiect care va avea acces la toate metodele și proprietățile atașate prototipului acelei funcții constructor.

Iată un exemplu de creare a unui obiect folosind o funcție constructor (vezi explicația codului la final):

function Person(firstname, lastname) {
    this.firstname = firstname;
    this.lastname = lastname;
}

Person.prototype.fullname = function() {
    console.log(this.firstname + ' ' + this.lastname);
}

var zubaer = new Person('Zubaer', 'Ahammed');
var john = new Person('John', 'Doe');

zubaer.fullname();
john.fullname();

Acum, poți crea câte obiecte vrei prin instanțierea funcției constructor Person și toate vor moșteni fullname() de la aceasta.

Notă: Cuvântul cheie „this” se va referi la un obiect gol în cadrul unei funcții constructor și ori de câte ori creezi un obiect nou din Person folosind operatorul „new”, acesta va returna automat un obiect care conține toate proprietățile și metodele atașate cu cuvântul cheie „this”. Și aceste obiecte vor moșteni cu siguranță metodele și proprietățile atașate la prototype-ul funcției constructor Person (care este principalul avantaj al acestei abordări).

Apropo, dacă ați fi vrut să obțineți aceeași funcționalitate cu sintaxa "literal de obiect", ar fi trebuit să creați fullname() pentru toate obiectele, astfel:

var zubaer = {
    firstname: 'Zubaer',
    lastname: 'Ahammed',
    fullname: function() {
        console.log(this.firstname + ' ' + this.lastname);
    }
};

var john= {
    firstname: 'John',
    lastname: 'Doe',
    fullname: function() {
        console.log(this.firstname + ' ' + this.lastname);
    }
};

zubaer.fullname();
john.fullname();

În cele din urmă, dacă acum întrebați de ce ar trebui să folosesc abordarea funcției constructor în locul abordării literale a obiectului:

*** Moștenirea prototipală permite un lanț simplu de moștenire care poate fi extrem de util și puternic.

*** Economisește memorie prin moștenirea metodelor și proprietăților comune definite în prototipul funcțiilor constructor. În caz contrar, ar trebui să le copiezi din nou și din nou în toate obiectele.

Sper că acest lucru are sens.

Răspunsul #7

De asemenea, conform unora dintre cărțile de javascript ale lui O'Really....(citare)

Un alt motiv pentru utilizarea literalelor în locul constructorului Object este că nu există rezoluție a domeniului de vizibilitate. Deoarece este posibil să fi creat un constructor local cu același nume, interpretul trebuie să parcurgă lanțul de domenii de vizibilitate de la locul unde ați apelat Object() până găsește constructorul Object global.