¿Cuál es la diferencia entre `new Object ()` y la notación literal de objeto?

199

¿Cuál es la diferencia entre esta sintaxis basada en constructor para crear un objeto?

person = new Object()

... y esta sintaxis literal:

person = {
    property1 : "Hello"
};

Parece que ambos hacen lo mismo, aunque JSLint prefiere que use notación literal de objeto.

¿Cuál es mejor y por qué?

ectype
fuente
77
De todos modos: a = new Object, a = new Object(), a = {}, literal es mucho más simple y algunas pruebas que corrió hace un tiempo dicen que es más rápido, más nuevos compiladores pueden haber causado mi declaración es falsa. Lo mismo se aplica a las matrices literales
Juan Mendes
8
Esperamos que esté declarando sus variables con la varpalabra clave en el código de su aplicación para evitar contaminar el espacio de nombres global y crear la necesidad de mirar más allá del registro actual en la pila para sus variables.
Samo
1
Básicamente, en cualquier momento durante la ejecución de un programa, hay una pila de registros o bloques. Cada registro tiene una lista de variables que se crearon en ese ámbito. En JavaScript, si una expresión contiene una variable y el intérprete no puede encontrarla en el registro de la pila para ese alcance, continuará avanzando al siguiente registro hasta que encuentre la variable. Más información davidshariff.com/blog/…
Samo
2
Evitar JSLint's es el primer paso para convertirse en un buen desarrollador. Usar newes una convención que trasciende el punto sin sentido de un lenguaje mediocre. Úselo newporque su significado es claro. En el 99,9% del caso, las ganancias de rendimiento son irrelevantes.
Hal50000
1
@ Hal50000 lenguaje mediocre según quién?
Xam

Respuestas:

124

Ambos hacen lo mismo (a menos que alguien haya hecho algo inusual), aparte de eso, el segundo crea un objeto y le agrega una propiedad. Pero la notación literal ocupa menos espacio en el código fuente. Es claramente reconocible en cuanto a lo que está sucediendo, por lo que al usarlo new Object(), realmente solo está escribiendo más y (en teoría, si no está optimizado por el motor JavaScript) haciendo una llamada de función innecesaria.

Estas

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

person = {
    property1 : "Hello"
};

técnicamente no hago lo mismo. El primero solo crea un objeto. El segundo crea uno y asigna una propiedad. Para que el primero sea el mismo, necesita un segundo paso para crear y asignar la propiedad.

El "algo inusual" que alguien podría hacer sería sombrear o asignar al Objectglobal predeterminado :

// Don't do this
Object = 23;

En ese caso altamente inusual , new Objectfallará pero {}funcionará.

En la práctica, nunca hay una razón para usar en new Objectlugar de {}(a menos que hayas hecho algo muy inusual).

kemiller2002
fuente
11
El autor eligió esta respuesta como correcta, pero está incompleta. Tenga en cuenta que existen diferencias entre las dos sintaxis cuando ingresa en la asignación de memoria.
newshorts
2
No hay diferencias Si te refieres a una de las respuestas a continuación, está fuera de tema, ya que habla sobre el modelo de objetos basado en prototipos y la herencia (el código allí configura una clase Obj que hereda de Object simple). Esta pregunta no se trata de crear una instancia de alguna clase personalizada, sino de crear una instancia de Object, y la respuesta correcta a esta pregunta es "no hay diferencia".
Dos
FYI tampoco () new Object()es obligatorio. (hablando de cosas no requeridas)
Royi Namir
Creo que no necesitamos usar nuevo a partir de la especificación actual. Déjame saber tus pensamientos @kevin
Vamsi Pavan Mahesh
1
También puede usar Object create y pass null si desea un objeto que no herede de la cadena de herencia. No son iguales y tienen propósitos útiles respectivamente.
Aaron
234

No hay diferencia para un objeto simple sin métodos como en su ejemplo. Sin embargo, hay una gran diferencia cuando comienzas a agregar métodos a tu objeto.

Forma literal:

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

Forma de prototipo:

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

Ambas formas permiten la creación de instancias Objcomo esta:

var foo = new Obj( "hello" ); 

Sin embargo, con la forma literal, llevas una copia del sayHellométodo dentro de cada instancia de tus objetos. Mientras que, con la forma del prototipo, el método se define en el prototipo del objeto y se comparte entre todas las instancias del objeto. Si tiene muchos objetos o muchos métodos, la forma literal puede conducir a un desperdicio de memoria bastante grande.

Rémy DAVID
fuente
39
Para mí, la pregunta era más sobre las diferencias entre usar new Object()vs {}para crear objetos vacíos.
Peter
11
@Lobabob Aparte de la primera oración, esta respuesta en realidad no proporciona ninguna información sobre la pregunta de OP. Ni siquiera contiene 'new Object ()' en ningún lado. Francamente, creo que el Sr. David no entendió la pregunta.
JLRishe
17
Cuando publiqué esto, la respuesta aceptada ya estaba allí y acepté. Y responde perfectamente a la pregunta de OP, así que no iba a repetir lo mismo. Publiqué mi respuesta principalmente para ampliar el tema más allá de los objetos vacíos / simples. En cuyo caso no es una diferencia importante que es digno de mención.
Rémy DAVID
3
Esta respuesta está fuera de tema. En su código, Obj es una clase separada que hereda de Object. Cuando usa la notación literal de objeto, usa la clase Object, no Obj. Por supuesto, configurar una clase con un método en su prototipo hará que la huella de la memoria sea más pequeña que crear muchos objetos simples y agregar métodos como sus propiedades, pero eso no tiene nada que ver con la pregunta que se hace aquí. La respuesta correcta a esta pregunta es "no, no hay absolutamente ninguna diferencia (tal vez excepto la legibilidad)".
Dos
3
Vine por esta respuesta, basada en una pregunta que era como la mía, pero terminé aprendiendo exactamente lo que necesitaba saber. Gracias.
Pat Migliaccio
55

En JavaScript, podemos declarar un nuevo objeto vacío de dos maneras:

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

No he encontrado nada que sugiera que hay una diferencia significativa entre estos dos con respecto a cómo operan detrás de escena (corríjame si estoy equivocado, me encantaría saberlo). Sin embargo, el segundo método (usando la notación literal del objeto) ofrece algunas ventajas.

  1. Es más corto (10 caracteres para ser precisos)
  2. Es más fácil y más estructurado crear objetos sobre la marcha.
  3. No importa si algún bufón ha anulado accidentalmente el objeto

Considere un nuevo objeto que contiene los miembros Nombre y TelNo. Usando la nueva convención Object (), podemos crearla así:

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

La característica de propiedades de Expando de JavaScript nos permite crear nuevos miembros de esta manera sobre la marcha, y logramos lo que pretendíamos. Sin embargo, esta forma no es muy estructurada o encapsulada. ¿Qué pasaría si quisiéramos especificar los miembros en el momento de la creación, sin tener que depender de las propiedades de expansión y la asignación posterior a la creación?

Aquí es donde la notación literal del objeto puede ayudar:

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

Aquí hemos logrado el mismo efecto en una línea de código y significativamente menos caracteres.

Puede encontrar más información sobre los métodos de construcción de objetos anteriores en: JavaScript y Programación Orientada a Objetos (OOP).

Y finalmente, ¿qué pasa con el idiota que anuló a Object? ¿Creías que no era posible? Bueno, este JSFiddle demuestra lo contrario. El uso de la notación literal del objeto nos impide caer en esta bufonada.

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

James Wiseman
fuente
1
¿Qué hay de Object.Create? Ver: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Phil
Si vas a favorecer los literales de objetos new Object()debido a la posibilidad de que algo sobrescriba la función Objeto, también deberías escribir guardias por todas partes cuando uses ayudantes Object.keyspara asegurarte de que no esté indefinido, lo que desciende a lo absurdo. Siempre recomendaría que las personas usen la notación literal, pero creo que este argumento en particular se desmorona cuando piensas en las consecuencias de pensar de esa manera.
philraj
41

En mi máquina usando Node.js, ejecuté lo siguiente:

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

Tenga en cuenta que esta es una extensión de lo que se encuentra aquí: ¿Por qué arr = [] es más rápido que arr = new Array?

mi salida fue la siguiente:

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

claramente {} y [] son ​​más rápidos que usar new para crear objetos / matrices vacíos.

rjloura
fuente
3
Siento que esta es la respuesta que la pregunta realmente estaba buscando, aunque me gustaría haber visto esto probado adicionalmente en un objeto con algunas propiedades para asegurarme.
Chase Sandmann
2
Números interesantes Hay personas que necesitan ser conscientes de esto, pero deduzco que asignar incluso unos escasos 200,000 objetos solo me costará 5.6ms, así que no me preocuparé por eso.
En el Nodo 10.13.0 las cosas HAN CAMBIADO Matriz de prueba: usando []: 117.178ms usando nuevo: 116.947ms Objeto de prueba: usando {}: 116.252ms usando nuevo: 115.910ms
PirateApp
31

Todos aquí están hablando de las similitudes de los dos. Voy a señalar las diferencias.

  1. Usar le new Object()permite pasar otro objeto. El resultado obvio es que el objeto recién creado se establecerá con la misma referencia. Aquí hay un código de muestra:

    var obj1 = new Object();
    obj1.a = 1;
    var obj2 = new Object(obj1);
    obj2.a // 1
  2. El uso no se limita a los objetos como en los objetos OOP. También se le podrían pasar otros tipos. La función establecerá el tipo en consecuencia. Por ejemplo, si le pasamos el número entero 1, se creará un objeto de tipo número.

    var obj = new Object(1);
    typeof obj // "number"
  3. El objeto creado usando el método anterior ( new Object(1)) se convertiría al tipo de objeto si se le agrega una propiedad.

    var obj = new Object(1);
    typeof obj // "number"
    obj.a = 2;
    typeof obj // "object"
  4. Si el objeto es una copia de una clase secundaria de objeto, podríamos agregar la propiedad sin la conversión de 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
Jermin Bazazian
fuente
3
Estoy muy confundido acerca de las dos últimas líneas. ¿Por qué si asigna a str.a el valor 1, str.a no está definido? .. @Jermin Bazazin
Andrea Scarafoni
3
@AndreaScarafoni porque stres de tipo, stringpor lo que no puede asignarle una propiedad. jsfiddle.net/grq6hdx7/1
Chris Bier
1
¿Ha cambiado la respuesta a 4? Me sale falso, no es cierto, en el último Chrome 53 var obj = new Object("foo"); typeof obj; obj === "foo" // true
William Hilton
21

En realidad, hay varias formas de crear objetos en JavaScript. Cuando solo desea crear un objeto, no hay beneficio de crear objetos " basados ​​en el constructor " utilizando el operador " nuevo ". Es lo mismo que crear un objeto usando la sintaxis " literal del objeto ". Pero los objetos " basados ​​en constructores " creados con el operador " nuevo " tienen un uso increíble cuando piensas en " herencia prototípica ". No puede mantener la cadena de herencia con objetos creados con sintaxis literal. Pero puede crear una función de constructor , adjuntar propiedades y métodos a su prototipo."operador, devolverá un objeto que tendrá acceso a todos los métodos y propiedades adjuntas con el prototipo de esa función constructora.

Aquí hay un ejemplo de cómo crear un objeto usando la función de constructor (vea la explicación del código en la parte inferior):

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

Ahora, puede crear tantos objetos como desee instanciando la función de construcción Persona y todos ellos heredarán el nombre completo () de ella.

Nota: " esta " palabra clave se referirá a un objeto vacío dentro de una función de constructor y cada vez que cree un nuevo objeto desde Persona usando el operador " nuevo ", devolverá automáticamente un objeto que contiene todas las propiedades y métodos adjuntos con la palabra clave " este " . Y estos objetos seguramente heredarán los métodos y propiedades asociados con el prototipo de la función de constructor Persona (que es la principal ventaja de este enfoque).

Por cierto, si desea obtener la misma funcionalidad con la sintaxis " literal de objeto ", tendría que crear el nombre completo () en todos los objetos como se muestra a continuación:

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

Por último, si ahora pregunta por qué debería usar el enfoque de función de constructor en lugar del enfoque literal de objeto :

*** La herencia prototípica permite una simple cadena de herencia que puede ser inmensamente útil y poderosa.

*** Ahorra memoria al heredar métodos comunes y propiedades definidas en el prototipo de funciones de constructor. De lo contrario, tendría que copiarlos una y otra vez en todos los objetos.

Espero que esto tenga sentido.

MD Zubaer Ahammed
fuente
¡Gracias! Karl por agregar el "this" que falta en el objeto literal. Fue un error horrible ... No debería haber cometido este tipo de error.
Md. Zubaer Ahammed
"No se puede heredar de un objeto creado con sintaxis literal". - No es cierto (creo). Puede usar Object.create(<object defined using literal notation>)o new Object(<object defined using literal notation>)y crear cadenas de herencia según sea necesario.
balajeerc
@balajeerc Gracias por tu comentario. En realidad debería ser "No se puede mantener la cadena de herencia con objetos creados con sintaxis literal". Las respuestas están en varios pasos: 1. Object.create (): Sí, es posible pasarle un literal de objeto y devolverá un nuevo objeto cuyo prototipo pasará al objeto literal. Pero no sabe qué es su función constructora o no recuerda el objeto literal del que fue creado. Entonces, testobj1.constructor devolverá una función vacía y no habrá forma de agregar propiedades / métodos a ese objeto literal como padre / ancestro.
Md. Zubaer Ahammed
@balajeerc 2. new Object (): Casi lo mismo sucede en este caso. Además, es peor si piensas en la memoria. En lugar de poner las propiedades y los métodos en su prototipo, simplemente copia todo del literal del objeto pasado y lo coloca en el objeto devuelto. No es bueno para la memoria. Por otro lado, me concentré en la verdadera cadena de herencia con una función de constructor donde puede editar métodos y propiedades sobre la marcha y otros objetos creados usando el método de constructor también se ven afectados ya que apuntan a esa función de constructor solamente (en lugar de copiarlos) .
Md. Zubaer Ahammed
@balajeerc Ejemplo: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

Además, según algunos de los libros de JavaScript de O'Really ... (citado)

Otra razón para usar literales en lugar del constructor de objetos es que no hay una resolución de alcance. Debido a que es posible que haya creado un constructor local con el mismo nombre, el intérprete debe buscar la cadena de alcance desde el lugar al que está llamando Object () hasta encontrar el constructor global de Object.

adolfo_isassi
fuente
24
Esperar, ¿fue O'Really un error tipográfico o un juego de palabras deliberado? ¡Deberían usar eso para comercializar sus libros!
Tim Ogilvy el
3

He encontrado una diferencia, para ES6 / ES2015. No puede devolver un objeto utilizando la sintaxis de la función de flecha abreviada, a menos que rodee el objeto con 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 } ]

Esto se debe a que el compilador está confundido por los {}corchetes y piensa que n: ies una etiqueta: construcción de declaración ; el punto y coma es opcional, por lo que no se queja.

Si agrega otra propiedad al objeto, finalmente arrojará un error.

$ 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 :
Andrei Simionescu
fuente
44
Todavía puede usar una función de flecha, solo necesita más llaves y un retorno: le [1, 2, 3].map(v => { return {n: v}; });dará lo mismo ...
Heretic Monkey
Por supuesto, puede usar funciones de flecha regulares, de lo que estaba hablando era de la versión abreviada, es decir param => return_value, y la diferencia entre usar {}y new Object()en este caso.
Andrei Simionescu
11
Todavía puede usar la versión abreviada Y las funciones de flecha regulares. Simplemente envuelva el {n: v} con un par de paréntesis:[1, 2, 3].map(v => ({n: v}));
Stephen C
1

Actualización 2019

Ejecuté el mismo código que @rjloura en mi nodo OSX High Sierra 10.13.6 versión 10.13.0 y estos son los resultados

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
PirateApp
fuente
-2

El uso de la memoria es diferente si crea 10 mil instancias. new Object()solo conservará una copia y {}conservará 10 mil copias.

Richard Miao EE. UU.
fuente
77
newCrea un nuevo objeto. Ambos toman la misma cantidad de memoria.
Artyer