javascript - Qual é a diferença entre `new Object()` e a notação literal de objeto?
Qual é a diferença entre esta sintaxe baseada em construtor para criar um objeto:
person = new Object()
...e esta sintaxe literal:
person = {
property1 : "Hello"
};
Parece que ambos fazem a mesma coisa, embora o JSLint prefira que você use a notação literal de objeto.
Qual é melhor e por quê?
Resposta #1
Não há diferença para um objeto simples sem métodos como no seu exemplo. No entanto, há uma grande diferença quando você começa a adicionar métodos ao seu objeto.
Forma literal:
function Obj( prop ) {
return {
p : prop,
sayHello : function(){ alert(this.p); },
};
}
Modo protótipo:
function Obj( prop ) {
this.p = prop;
}
Obj.prototype.sayHello = function(){alert(this.p);};
Ambos os métodos permitem a criação de instâncias de Obj assim:
var foo = new Obj( "hello" );
No entanto, com a forma literal, você carrega uma cópia do método sayHello dentro de cada instância de seus objetos. Enquanto isso, com a forma de protótipo, o método é definido no protótipo do objeto e compartilhado entre todas as instâncias do objeto. Se você tiver muitos objetos ou muitos métodos, a forma literal pode levar a um desperdício de memória bastante grande.
Resposta #2
Eles dois fazem a mesma coisa (a menos que alguém tenha feito algo incomum), além disso, o seu segundo cria um objeto e adiciona uma propriedade a ele. Mas a notação literal ocupa menos espaço no código-fonte. É claramente reconhecível o que está acontecendo, então usando new Object(), você está realmente apenas digitando mais e (em teoria, se não for otimizado pelo motor JavaScript) fazendo uma chamada de função desnecessária.
Estes
person = new Object() /*You should put a semicolon here too.
It's not required, but it is good practice.*/
-or-
person = {
property1 : "Hello"
};
tecnicamente não fazem a mesma coisa. O primeiro apenas cria um objeto. O segundo cria um e atribui uma propriedade. Para que o primeiro seja o mesmo, você precisa de uma segunda etapa para criar e atribuir a propriedade.
O "algo incomum" que alguém poderia fazer seria sombrear ou atribuir ao Object global padrão:
// Don't do this
Object = 23;
Nesse caso altamente incomum, new Object falhará, mas {} funcionará.
Na prática, nunca há razão para usar new Object em vez de {} (a menos que você tenha feito aquela coisa muito incomum).
Resposta #3
Em JavaScript, podemos declarar um novo objeto vazio de duas maneiras:
var obj1 = new Object();
var obj2 = {};
Não encontrei nada que sugira que haja alguma diferença significativa entre esses dois no que diz respeito a como eles funcionam nos bastidores (por favor, me corrija se eu estiver errado - eu adoraria saber). No entanto, o segundo método (usando a notação literal de objeto) oferece algumas vantagens.
- É mais curto (10 caracteres para ser preciso)
- É mais fácil e mais estruturado criar objetos rapidamente
- Não importa se algum bufão substituiu acidentalmente o Object
Considere um novo objeto que contém os membros Name e TelNo. Usando a convenção new Object(), podemos criá-lo assim:
var obj1 = new Object();
obj1.Name = "A Person";
obj1.TelNo = "12345";
O recurso Expando Properties do JavaScript nos permite criar novos membros dessa forma dinamicamente, e conseguimos o que estávamos pretendendo. No entanto, essa forma não é muito estruturada ou encapsulada. E se quiséssemos especificar os membros na criação, sem ter que depender de propriedades expando e atribuição após a criação?
É aqui que a notação literal de objetos pode ajudar:
var obj1 = { Name: "A Person", TelNo: "12345" };
Aqui conseguimos o mesmo efeito em uma linha de código e com significativamente menos caracteres.
Uma discussão adicional sobre os métodos de construção de objetos acima pode ser encontrada em: JavaScript e Programação Orientada a Objetos (OOP).
E finalmente, e quanto ao idiota que sobrescreveu o Object? Você achou que não era possível? Bem, este JSFiddle prova o contrário. Usar a notação literal de objeto nos impede de cair nessa bobagem.
(De http://www.jameswiseman.com/blog/2011/01/19/jslint-messages-use-the-object-literal-notation/)
Resposta #4
Na minha máquina usando Node.js, eu executei o seguinte:
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');
Observe, isto é uma extensão do que é encontrado aqui: Por que arr=[] é mais rápido do que arr=new Array?
meu resultado foi o seguinte:
Testing Array:
using[]: 1091ms
using new: 2286ms
Testing Object:
using{}: 870ms
using new: 5637ms
portanto, claramente {} e [] são mais rápidos do que usar new para criar objetos/arrays vazios.
Resposta #5
Todos aqui estão falando sobre as semelhanças dos dois. Eu vou apontar as diferenças.
Usar
new Object()permite que você passe outro objeto. O resultado óbvio é que o objeto recém-criado será definido para a mesma referência. Aqui está um código de exemplo:var obj1 = new Object(); obj1.a = 1; var obj2 = new Object(obj1); obj2.a // 1O uso não se limita a objetos como em objetos de OOP. Outros tipos também podem ser passados para ele. A função definirá o tipo de acordo. Por exemplo, se passarmos o inteiro 1 para ele, um objeto do tipo número será criado para nós.
var obj = new Object(1); typeof obj // "number"O objeto criado usando o método acima (
new Object(1)) seria convertido para o tipo objeto se uma propriedade for adicionada a ele.var obj = new Object(1); typeof obj // "number" obj.a = 2; typeof obj // "object"Se o objeto é uma cópia de uma classe filha de objeto, poderíamos adicionar a propriedade sem a conversão 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
Resposta #6
Na verdade, existem várias maneiras de criar objetos em JavaScript. Quando você só quer criar um objeto, não há vantagem em criar objetos "baseados em construtor" usando o operador "new". É o mesmo que criar um objeto usando a sintaxe de "literal de objeto". Mas os objetos "baseados em construtor" criados com o operador "new" são extremamente úteis quando você está pensando em "herança prototípica". Você não pode manter a cadeia de herança com objetos criados com a sintaxe literal. Mas você pode criar uma função construtora, anexar propriedades e métodos ao seu protótipo. Então, se você atribuir essa função construtora a qualquer variável usando o operador new, ela retornará um objeto que terá acesso a todos os métodos e propriedades anexados ao protótipo dessa função construtora.
Aqui está um exemplo de criação de um objeto usando uma função construtora (veja a explicação do código na 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();
Agora, você pode criar quantos objetos quiser instanciando a função construtora Person e todos eles herdarão fullname() dela.
Observação: a palavra-chave "this" se referirá a um objeto vazio dentro de uma função construtora e sempre que você criar um novo objeto a partir de Person usando o operador "new", ele retornará automaticamente um objeto contendo todas as propriedades e métodos vinculados à palavra-chave "this". E esse objeto certamente herdará os métodos e propriedades vinculados ao prototype da função construtora Person (que é a principal vantagem dessa abordagem).
A propósito, se você quisesse obter a mesma funcionalidade com a sintaxe de "objeto literal", você teria que criar fullname() em todos os objetos como abaixo:
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 fim, se você agora perguntar por que deveria usar a abordagem de função construtora em vez da abordagem de objeto literal:
*** A herança prototípica permite uma cadeia simples de herança que pode ser imensamente útil e poderosa.
*** Economiza memória ao herdar métodos e propriedades comuns definidos no protótipo das funções construtoras. Caso contrário, você teria que copiá-los repetidamente em todos os objetos.
Espero que isso faça sentido.
Resposta #7
Além disso, de acordo com alguns dos livros de JavaScript do O'Reilly....(citado)
Outro motivo para usar literais em vez do construtor Object é que não há resolução de escopo. Como é possível que você tenha criado um construtor local com o mesmo nome, o interpretador precisa verificar a cadeia de escopo desde o local onde você está chamando Object() até encontrar o construtor Object global.
