Búsqueda de sitios web

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


¿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 uses la notación literal de objetos.

¿Cuál es mejor y por qué?

Respuesta #1

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

Manera 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 de Obj así:

var foo = new Obj( "hello" ); 

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

Respuesta #2

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

Estos

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 hacen lo mismo. El primero solo crea un objeto. El segundo crea uno y asigna una propiedad. Para que el primero sea igual, entonces necesitas un segundo paso para crear y asignar la propiedad.

Lo "algo inusual" que alguien podría hacer sería sombrear o asignar al Object global por defecto:

// Don't do this
Object = 23;

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

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

Respuesta #3

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 haya alguna diferencia significativa entre estos dos con respecto a cómo funcionan detrás de escena (por favor corríjanme si me equivoco; me encantaría saberlo). Sin embargo, el segundo método (usando la notación literal de objetos) 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 sobrescrito inadvertidamente Object

Considera un nuevo objeto que contiene los miembros Name y TelNo. Usando la convención new Object(), podemos crearlo así:

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

La función de Propiedades Expando de JavaScript nos permite crear nuevos miembros de esta manera sobre la marcha, y logramos lo que queríamos. Sin embargo, esta manera no es muy estructurada ni encapsulada. ¿Qué pasaría si quisiéramos especificar los miembros al momento de la creación, sin tener que depender de propiedades expando y asignaciones posteriores a la creación?

Aquí es donde la notación literal de objetos puede ayudar:

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

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

Se puede encontrar una discusión adicional sobre los métodos de construcción de objetos mencionados arriba en: JavaScript y Programación Orientada a Objetos (OOP).

Y finalmente, ¿qué pasa con el idiota que anuló Object? ¿Pensaste que no era posible? Bueno, este JSFiddle demuestra lo contrario. Usar la notación literal de objetos nos previene de caer en esta tontería.

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

Respuesta #4

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

Nota, esto 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

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

Respuesta #5

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

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

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

    var obj = new Object(1);
    typeof obj // "number"
    
  3. El objeto creado usando el método anterior (new Object(1)) se convertiría en tipo 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 hija 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
    

Respuesta #6

En realidad, hay varias formas de crear objetos en JavaScript. Cuando solo quieres crear un objeto, no hay beneficio en crear objetos "basados en constructor" usando el operador "new". Es lo mismo que crear un objeto usando la sintaxis de "literal de objeto". Pero los objetos "basados en constructor" creados con el operador "new" resultan de un uso increíble cuando estás pensando en la "herencia prototípica". No se puede mantener la cadena de herencia con objetos creados con sintaxis literal. Pero se puede crear una función constructora, adjuntar propiedades y métodos a su prototipo. Luego, si asignas esta función constructora a cualquier variable usando el operador "new", devolverá un objeto que tendrá acceso a todos los métodos y propiedades adjuntos al prototipo de esa función constructora.

Aquí hay un ejemplo de cómo crear un objeto usando una función constructora (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, puedes crear tantos objetos como quieras instanciando la función constructora Person y todos ellos heredarán fullname() de ella.

Nota: la palabra clave "this" se referirá a un objeto vacío dentro de una función constructora y cada vez que crees un nuevo objeto de Person usando el operador "new" automáticamente devolverá un objeto que contiene todas las propiedades y métodos asociados con la palabra clave "this". Y este objeto seguramente heredará los métodos y propiedades asociados con el prototype de la función constructora Person (que es la principal ventaja de este enfoque).

Por cierto, si quisieras obtener la misma funcionalidad con la sintaxis de "literal de objeto", tendrías que crear fullname() 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 te preguntas por qué debería usar el enfoque de función constructora en lugar del enfoque de literal de objeto:

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

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

Espero que esto tenga sentido.

Respuesta #7

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

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

Artículos relacionados