Pesquisa de site

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.

  1. É mais curto (10 caracteres para ser preciso)
  2. É mais fácil e mais estruturado criar objetos rapidamente
  3. 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.

  1. 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 // 1
    
  2. O 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"
    
  3. 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"
    
  4. 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.

Artigos relacionados