Qual è la differenza tra `new Object ()` e object notation letterale?


199

Qual è la differenza tra questa sintassi basata sul costruttore per la creazione di un oggetto:

person = new Object()

... e questa sintassi letterale:

person = {
    property1 : "Hello"
};

Sembra che entrambi facciano la stessa cosa, sebbene JSLint preferisca usare la notazione letterale dell'oggetto.

Quale è meglio e perchè?


7
Tutti uguali: a = new Object, a = new Object(), a = {}, letterale è molto più semplice e alcuni test mi sono imbattuto qualche tempo fa dire che è più veloce, i compilatori recenti possono aver causato la mia dichiarazione di essere falsa. Lo stesso vale per gli array letterali
Juan Mendes,

8
Spero che tu stia dichiarando le tue variabili con la varparola chiave nel codice dell'applicazione per evitare di inquinare lo spazio dei nomi globale e creare la necessità di guardare oltre il record corrente nello stack per le tue variabili.
Samo,

1
Fondamentalmente, in qualsiasi momento durante l'esecuzione di un programma, c'è una pila di record o blocchi. Ogni record ha un elenco di variabili che sono state create in quell'ambito. In JavaScript, se un'espressione contiene una variabile e l'interprete non riesce a trovarla nel record dello stack per quell'ambito, continuerà a passare al record successivo fino a quando non trova la variabile. Maggiori informazioni davidshariff.com/blog/…
Samo,

2
Evitare JSLint è il primo passo per diventare un buon sviluppatore. L'utilizzo newè una convenzione che trascende il inutile pignolo di un linguaggio mediocre. Utilizzare newperché il suo significato è chiaro. Nel 99,9% dei casi, i miglioramenti delle prestazioni sono irrilevanti.
Hal50000,

1
@ Hal50000 linguaggio mediocre secondo chi?
Xam,

Risposte:


124

Entrambi fanno la stessa cosa (a meno che qualcuno non abbia fatto qualcosa di insolito), a parte il fatto che il secondo crea un oggetto e aggiunge una proprietà ad esso. Ma la notazione letterale occupa meno spazio nel codice sorgente. È chiaramente riconoscibile ciò che sta accadendo, quindi usando new Object(), stai davvero scrivendo di più e (in teoria, se non ottimizzato dal motore JavaScript) facendo una chiamata di funzione non necessaria.

Questi

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

person = {
    property1 : "Hello"
};

tecnicamente non fare la stessa cosa. Il primo crea solo un oggetto. Il secondo ne crea uno e assegna una proprietà. Affinché il primo sia lo stesso, è necessario un secondo passaggio per creare e assegnare la proprietà.

Il "qualcosa di insolito" che qualcuno potrebbe fare sarebbe ombreggiare o assegnare al Objectglobale predefinito :

// Don't do this
Object = 23;

In quel caso insolito , new Objectfallirà ma{} funzionerà.

In pratica, non c'è mai un motivo per usarlo new Objectpiuttosto che {}(a meno che tu non abbia fatto una cosa molto insolita).


11
L'autore ha scelto questa risposta come corretta, ma è incompleta. Tenere presente che esistono differenze tra le due sintassi quando si entra nell'allocazione della memoria.
Newshorts

2
Non ci sono differenze Se ti riferisci a una delle risposte sotto, è fuori tema, in quanto parla del modello di oggetti basato sul prototipo e dell'ereditarietà (il codice lì imposta una classe Obj che eredita dal semplice oggetto). Questa domanda non riguarda la creazione di un'istanza di una classe personalizzata, ma la creazione di un'istanza di Object e la risposta corretta a questa domanda è "non c'è differenza".
dos

FYI inoltre () new Object()non è richiesto. (parlando di cose non richieste)
Royi Namir,

Penso che non abbiamo bisogno di usare il nuovo come dalle attuali specifiche. Fammi sapere cosa
pensi

1
È inoltre possibile utilizzare Object create e passare null se si desidera un oggetto che non eredita dalla catena di ereditarietà. Non sono uguali e hanno scopi utili rispettivamente.
Aaron,

234

Non c'è differenza per un oggetto semplice senza metodi come nel tuo esempio. Tuttavia, c'è una grande differenza quando inizi ad aggiungere metodi al tuo oggetto.

Modo letterale:

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

Modo prototipo:

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

Entrambi i modi consentono la creazione di istanze di Objquesto tipo:

var foo = new Obj( "hello" ); 

Tuttavia, con il metodo letterale, porti una copia del sayHellometodo all'interno di ogni istanza dei tuoi oggetti. Considerando che, con il metodo prototipo, il metodo è definito nel prototipo dell'oggetto e condiviso tra tutte le istanze dell'oggetto. Se hai molti oggetti o molti metodi, il modo letterale può portare a grandi sprechi di memoria.


39
Per me la domanda era più sulle differenze tra usare new Object()vs {}per creare oggetti vuoti.
Peter,

11
@Lobabob A parte la prima frase, questa risposta in realtà non fornisce alcuna informazione sulla domanda di OP. Non contiene nemmeno 'new Object () `ovunque. Francamente, penso che il signor David abbia frainteso la domanda.
JLRishe,

17
Quando l'ho pubblicato, la risposta accettata era già lì e accettata. E risponde perfettamente alla domanda del PO, quindi non avrei ripetuto la stessa cosa. Ho pubblicato la mia risposta principalmente per ampliare il soggetto oltre gli oggetti vuoti / semplici. Nel qual caso è una differenza importante che la pena ricordare.
Rémy DAVID,

3
Questa risposta è fuori tema. Nel tuo codice, Obj è una classe separata che eredita da Object. Quando usi la notazione letterale dell'oggetto, usi la classe Object, non Obj. Ovviamente, impostare una classe con il metodo nel suo prototipo ridurrà il footprint della memoria piuttosto che creare molti oggetti semplici e aggiungere il metodo come loro proprietà, ma questo è completamente estraneo alla domanda qui posta. La risposta corretta a questa domanda è "no, non c'è assolutamente alcuna differenza (forse tranne la leggibilità)".
dos

3
Sono venuto per questa risposta, basato su una domanda che era un po 'come la mia, ma ho finito per imparare esattamente quello che dovevo sapere. Grazie.
Pat Migliaccio,

55

In JavaScript, possiamo dichiarare un nuovo oggetto vuoto in due modi:

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

Non ho trovato nulla che suggerisca che ci siano differenze significative tra questi due riguardo al modo in cui operano dietro le quinte (per favore correggimi se sbaglio, mi piacerebbe saperlo). Tuttavia, il secondo metodo (utilizzando la notazione letterale dell'oggetto) offre alcuni vantaggi.

  1. È più corto (10 caratteri per essere precisi)
  2. È più facile e più strutturato creare oggetti al volo
  3. Non importa se un buffone ha ignorato involontariamente l'Oggetto

Considera un nuovo oggetto che contiene i membri Nome e TelNo. Usando la nuova convenzione Object (), possiamo crearla in questo modo:

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

Le proprietà di Expando di JavaScript ci consente di creare nuovi membri in questo modo al volo e raggiungiamo ciò che intendevamo. Tuttavia, in questo modo non è molto strutturato o incapsulato. E se volessimo specificare i membri al momento della creazione, senza dover fare affidamento su expando proprietà e assegnazione post-creazione?

Qui è dove la notazione letterale dell'oggetto può aiutare:

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

Qui abbiamo ottenuto lo stesso effetto in una riga di codice e significativamente meno caratteri.

Un'ulteriore discussione sui metodi di costruzione degli oggetti sopra è disponibile su: JavaScript e Object Oriented Programming (OOP).

E infine, che dire dell'idiota che ha scavalcato l'Oggetto? Pensavi che non fosse possibile? Bene, questo JSFiddle dimostra il contrario. L'uso della notazione letterale dell'oggetto ci impedisce di cadere nel fallo di questa buffoneria.

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



Se hai intenzione di privilegiare i letterali degli oggetti a new Object()causa della possibilità che qualcosa sovrascriva la funzione Oggetto, dovresti anche scrivere guardie dappertutto quando usi aiutanti come Object.keysper assicurarti che non sia indefinito, il che scende in assurdità. Consiglierei sempre alle persone di usare la notazione letterale, ma penso che questo particolare argomento cada a pezzi quando pensi alle conseguenze di pensare in quel modo.
philraj,

41

Sul mio computer utilizzando Node.js, ho eseguito il seguente:

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');

Nota, questa è un'estensione di ciò che si trova qui: Perché arr = [] è più veloce di arr = new Array?

la mia uscita è stata la seguente:

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

così chiaramente {} e [] sono più veloci dell'uso di new per la creazione di oggetti / array vuoti.


3
Sento che questa è la risposta che la domanda stava davvero cercando, anche se mi piacerebbe vederlo testato ulteriormente su un oggetto con alcune proprietà per essere sicuro.
Chase Sandmann,

2
Numeri interessanti Ci sono persone che devono esserne consapevoli, ma tolgo che l'assegnazione anche di un misero 200.000 oggetti mi costerà solo 5,6 milioni, quindi non me ne preoccuperò.

Sul nodo 10.13.0 le cose HANNO CAMBIATO Matrice di test: usando []: 117.178ms usando nuovo: 116.947ms Oggetto di test: usando {}: 116.252ms usando nuovo: 115.910ms
PirateApp

31

Tutti qui parlano delle somiglianze dei due. Indicherò le differenze.

  1. L'uso new Object()consente di passare un altro oggetto. Il risultato ovvio è che l'oggetto appena creato verrà impostato sullo stesso riferimento. Ecco un codice di esempio:

    var obj1 = new Object();
    obj1.a = 1;
    var obj2 = new Object(obj1);
    obj2.a // 1
  2. L'uso non è limitato agli oggetti come negli oggetti OOP. Altri tipi potrebbero essere passati anche ad esso. La funzione imposterà il tipo di conseguenza. Ad esempio, se gli passiamo il numero intero 1, verrà creato per noi un oggetto di tipo numero.

    var obj = new Object(1);
    typeof obj // "number"
  3. L'oggetto creato utilizzando il metodo sopra ( new Object(1)) verrebbe convertito nel tipo di oggetto se una proprietà viene aggiunta ad esso.

    var obj = new Object(1);
    typeof obj // "number"
    obj.a = 2;
    typeof obj // "object"
  4. Se l'oggetto è una copia di una classe di oggetti figlio, è possibile aggiungere la proprietà senza la conversione del tipo.

    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

3
sono molto confuso riguardo alle ultime due righe .. Perché se assegni a str.a il valore 1, str.a non è definito? .. @Jermin Bazazin
Andrea Scarafoni

3
@AndreaScarafoni perché strè di tipo, stringquindi non puoi assegnargli una proprietà. jsfiddle.net/grq6hdx7/1
Chris Bier,

1
La risposta a 4 è cambiata? Ottengo falso, non vero, nell'ultimo Chrome 53 var obj = new Object("foo"); typeof obj; obj === "foo" // true
William Hilton,

21

In realtà, ci sono diversi modi per creare oggetti in JavaScript. Quando si desidera solo creare un oggetto, non si ha alcun vantaggio nel creare oggetti " basati sul costruttore " utilizzando l' operatore " nuovo ". È come creare un oggetto usando la sintassi " letterale oggetto ". Ma gli oggetti " basati su costruttori " creati con un " nuovo " operatore sono incredibilmente utili quando si pensa alla " eredità prototipale ". Non è possibile mantenere la catena di ereditarietà con oggetti creati con sintassi letterale. Ma puoi creare una funzione di costruzione , associare proprietà e metodi al suo prototipo."operatore, restituirà un oggetto che avrà accesso a tutti i metodi e proprietà associati al prototipo di quella funzione di costruzione.

Ecco un esempio di creazione di un oggetto utilizzando la funzione di costruzione (vedere la spiegazione del codice in basso):

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

Ora puoi creare tutti gli oggetti che vuoi istanziando la funzione di costruzione Person e tutti erediteranno fullname () da esso.

Nota: la parola chiave " this " farà riferimento a un oggetto vuoto all'interno di una funzione di costruzione e ogni volta che si crea un nuovo oggetto da Person utilizzando l' operatore " new ", verrà automaticamente restituito un oggetto contenente tutte le proprietà e i metodi associati alla parola chiave " this " . E questi oggetti erediteranno sicuramente i metodi e le proprietà associati al prototipo della funzione di costruzione Person (che è il vantaggio principale di questo approccio).

A proposito, se si desidera ottenere la stessa funzionalità con la sintassi " letterale oggetto ", è necessario creare fullname () su tutti gli oggetti come di seguito:

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

Alla fine, se ora mi chiedi perché dovrei usare l' approccio della funzione di costruzione anziché l' oggetto letterale approccio :

*** L'eredità prototipale consente una semplice catena di eredità che può essere immensamente utile e potente.

*** Risparmia memoria ereditando metodi e proprietà comuni definiti nel prototipo delle funzioni di costruzione. Altrimenti, dovresti copiarli più e più volte in tutti gli oggetti.

Spero che abbia senso.


Grazie! Karl per aver aggiunto il "questo" mancante nell'oggetto letterale. È stato un errore orribile ... Non avrei dovuto commettere questo tipo di errore.
Md. Zubaer Ahammed,

"Non puoi ereditare da un oggetto creato con sintassi letterale." - Non è vero (credo). È possibile utilizzare Object.create(<object defined using literal notation>)o new Object(<object defined using literal notation>)e creare catene di ereditarietà secondo necessità.
balajeerc,

@balajeerc Grazie per il tuo commento. In realtà dovrebbe essere "Non è possibile mantenere la catena di ereditarietà con oggetti creati con sintassi letterale". La risposta è in più passaggi: 1. Object.create (): Sì, è possibile passare un oggetto letteralmente ad esso e restituirà un nuovo oggetto quale prototipo passerà letteralmente all'oggetto. Ma non sa quale sia la sua funzione di costruzione o non ricordi quell'oggetto letterale da cui è stato creato. Quindi, testobj1.constructor restituirà una funzione vuota e non ci sarà modo di aggiungere proprietà / metodi a quell'oggetto letterale come genitore / antenato.
Md. Zubaer Ahammed,

@balajeerc 2. new Object (): in questo caso accade quasi la stessa cosa. Inoltre, è peggio se pensi alla memoria. Invece di mettere le proprietà e i metodi sul suo prototipo, copia letteralmente tutto dall'oggetto passato e lo inserisce nell'oggetto restituito. Non fa bene alla memoria. D'altra parte, mi sono concentrato sulla vera catena di ereditarietà con una funzione di costruzione in cui è possibile modificare metodi e proprietà al volo e anche altri oggetti creati utilizzando il metodo di costruzione sono interessati dal fatto che puntano solo a quella funzione di costruzione (invece di copiarli) .
Md. Zubaer Ahammed,

@balajeerc Esempio: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(); // Zubaer Ahammed john.fullname(); // John Doe zubaer.constructor.prototype.fullname = function() { console.log( 'Hello ' + this.firstname); } zubaer.fullname(); // Hello Zubaer john.fullname(); // Hoello John
Md. Zubaer Ahammed,

9

Inoltre, secondo alcuni dei libri javascript di O'Really .... (citato)

Un altro motivo per usare valori letterali rispetto al costruttore Object è che non esiste una risoluzione dell'ambito. Poiché è possibile che sia stato creato un costruttore locale con lo stesso nome, l'interprete deve cercare la catena dell'ambito dal punto in cui si chiama Object () fino a quando non trova il costruttore Object globale.


24
aspetta O'Really era un refuso o un gioco di parole deliberato? Dovrebbero usarlo per commercializzare i loro libri!
Tim Ogilvy,

3

Ho trovato una differenza, per ES6 / ES2015. Non è possibile restituire un oggetto utilizzando la sintassi della funzione freccia abbreviata, a meno che non si contorni l'oggetto new Object().

> [1, 2, 3].map(v => {n: v});
[ undefined, undefined, undefined ]
> [1, 2, 3].map(v => new Object({n: v}));
[ { n: 1 }, { n: 2 }, { n: 3 } ]

Questo perché il compilatore è confuso tra {}parentesi e pensa che n: isia un'etichetta: istruzione ; il punto e virgola è facoltativo, quindi non se ne lamenta.

Se aggiungi un'altra proprietà all'oggetto, verrà generato un errore.

$ node -e "[1, 2, 3].map(v => {n: v, m: v+1});"
[1, 2, 3].map(v => {n: v, m: v+1});
                           ^

SyntaxError: Unexpected token :

4
Puoi ancora usare una funzione freccia, hai solo bisogno di più parentesi graffe e un ritorno: [1, 2, 3].map(v => { return {n: v}; });ti metterà in rete la stessa cosa ...
Heretic Monkey

Ovviamente puoi usare le normali funzioni delle frecce, quello di cui parlavo era la versione abbreviata, cioè param => return_value, e la differenza tra l'utilizzo {}e new Object()in questo caso.
Andrei Simionescu,

11
Puoi ancora utilizzare la versione abbreviata E le normali funzioni delle frecce. Basta avvolgere {n: v} con un paio di parentesi:[1, 2, 3].map(v => ({n: v}));
Stephen C

1

Aggiornamento 2019

Ho eseguito lo stesso codice di @rjloura sul mio nodo OSX High Sierra 10.13.6 versione 10.13.0 e questi sono i risultati

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');


Testing Array:
using[]: 117.613ms
using new: 117.168ms
Testing Object:
using{}: 117.205ms
using new: 118.644ms

-2

L'uso della memoria è diverso se si creano 10 mila istanze. new Object()conserverà solo una copia mentre {}ne conserverà 10 mila copie.


7
newcrea un nuovo oggetto. Entrambi occupano la stessa quantità di memoria.
Artyer,
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.