Qual é a diferença entre `new Object ()` e notação literal de objeto?

199

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 os dois fazem a mesma coisa, embora o JSLint prefira o uso da notação literal do objeto.

Qual deles é melhor e por quê?

ectype
fonte
7
Tudo a mesma coisa: a = new Object, a = new Object(), a = {}, literal é muito mais simples e alguns testes eu corri um tempo atrás dizem que é mais rápido, compiladores mais recentes podem ter causado a minha declaração é falsa. O mesmo se aplica a matrizes literais
Juan Mendes
8
Espero que você esteja declarando suas variáveis ​​com a varpalavra - chave no código do aplicativo para evitar poluir o espaço para nome global e criar a necessidade de procurar além das variáveis ​​no registro atual da pilha.
Samo
1
Basicamente, a qualquer momento durante a execução de um programa, há uma pilha de registros ou blocos. Cada registro possui uma lista de variáveis ​​que foram criadas nesse escopo. Em JavaScript, se uma expressão contiver uma variável e o intérprete não puder encontrá-la no registro da pilha para esse escopo, ela continuará subindo para o próximo registro até encontrar a variável. Mais informações davidshariff.com/blog/…
Samo
2
Evitar o JSLint é o primeiro passo para se tornar um bom desenvolvedor. O uso newé uma convenção que transcende a busca inútil de uma linguagem medíocre. Use newporque seu significado é claro. Em 99,9% dos casos, os ganhos de desempenho são irrelevantes.
Hal50000
1
@ Linguagem medíocre Hal50000 de acordo com quem?
Xam

Respostas:

124

Ambos fazem a mesma coisa (a menos que alguém tenha feito algo incomum), exceto que 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; portanto, usando new Object(), você está apenas digitando mais e (em teoria, se não for otimizado pelo mecanismo 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 faça 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ê precisará de uma segunda etapa para criar e atribuir a propriedade.

O "algo incomum" que alguém poderia fazer seria sombrear ou atribuir ao Objectglobal padrão :

// Don't do this
Object = 23;

Nesse caso altamente incomum , new Objectfalhará, mas {}funcionará.

Na prática, nunca há uma razão para usar new Objectem vez de {}(a menos que você tenha feito essa coisa muito incomum).

kemiller2002
fonte
11
O autor escolheu esta resposta como correta, mas está incompleta. Esteja ciente de que existem diferenças entre as duas sintaxes ao entrar na alocação de memória.
Newshorts
2
Não há diferenças. Se você está se referindo a uma das respostas abaixo, é fora de tópico, pois está falando sobre modelo e herança de objeto baseado em protótipo (o código lá configura uma classe Obj que herda de Object simples). Esta pergunta não é sobre a criação de uma instância de alguma classe personalizada - é sobre a criação de instância do Object, e a resposta correta para esta pergunta é "não há diferença".
dos
FYI também () new Object()não é necessário. (Falando coisinha sobre não obrigatório)
Royi Namir
Acho que não precisamos usar novos como na especificação atual. Deixe-me saber seus pensamentos @ Kevin
Vamsi Pavan Mahesh
1
Você também pode usar a criação de objeto e passar nulo se desejar um objeto que não herda da cadeia de herança. Eles não são iguais e têm finalidades úteis, respectivamente.
Aaron
234

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.

Maneira literal:

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

Maneira do protótipo:

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

Ambas as formas permitem a criação de instâncias Objcomo esta:

var foo = new Obj( "hello" ); 

No entanto, com a maneira literal, você carrega uma cópia do sayHellométodo dentro de cada instância de seus objetos. Enquanto que, da maneira do protótipo, o método é definido no protótipo do objeto e compartilhado entre todas as instâncias do objeto. Se você tem muitos objetos ou muitos métodos, a maneira literal pode levar a um desperdício de memória bastante grande.

Rémy DAVID
fonte
39
Para mim, a questão era mais sobre as diferenças entre usar new Object()vs {}para criar objetos vazios.
Peter
11
@Lobabob Além da primeira frase, esta resposta não fornece nenhuma informação sobre a pergunta do OP. Ele nem contém 'new Object () `em lugar nenhum. Francamente, acho que o Sr. David não entendeu a pergunta.
JLRishe
17
Quando postei isso, a resposta aceita já estava lá e foi aceita. E responde perfeitamente à pergunta do OP, para que eu não repetisse a mesma coisa. Postei minha resposta principalmente para ampliar o assunto além de objetos vazios / simples. Caso em que não é uma diferença importante que vale a pena mencionar.
Rémy DAVID
3
Esta resposta está fora de tópico. No seu código, Obj é uma classe separada que herda de Object. Ao usar a notação literal de objeto, você usa a classe Object, não a Obj. É claro que configurar uma classe com método em seu protótipo reduzirá o espaço de memória do que criar muitos objetos simples e adicionar método como suas propriedades, mas isso não tem nenhuma relação com a pergunta feita aqui. A resposta correta para esta pergunta é "não, não há absolutamente nenhuma diferença (talvez exceto a legibilidade)".
dos
3
Eu vim para esta resposta, com base em uma pergunta que era como a minha, mas acabei aprendendo exatamente o que eu precisava saber. Obrigado.
Pat Migliaccio
55

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 com relação à maneira como eles operam nos bastidores (por favor, corrija-me se estiver errado - adoraria saber). No entanto, o segundo método (usando a notação literal do objeto) oferece algumas vantagens.

  1. É mais curto (10 caracteres para ser mais preciso)
  2. É mais fácil e mais estruturado para criar objetos em tempo real
  3. Não importa se algum bufão substituiu inadvertidamente o objeto

Considere um novo objeto que contém os membros Name e TelNo. Usando a nova convenção Object (), podemos criá-la assim:

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

O recurso Expando Properties do JavaScript nos permite criar novos membros dessa maneira em tempo real, e alcançamos o que pretendíamos. No entanto, esse caminho não é muito estruturado ou encapsulado. E se quiséssemos especificar os membros na criação, sem precisar confiar nas propriedades expando e na pós-criação da atribuição?

É aqui que a notação literal do objeto pode ajudar:

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

Aqui alcançamos o mesmo efeito em uma linha de código e significativamente menos caracteres.

Uma discussão adicional sobre os métodos de construção de objetos acima pode ser encontrada em: JavaScript e Object Oriented Programming (OOP).

E, finalmente, o que dizer do idiota que substituiu Object? Você achou que não era possível? Bem, esse JSFiddle prova o contrário. O uso da notação literal de objeto nos impede de cair em desgraça com esse bufão.

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

James Wiseman
fonte
Se você prefere os literais de objetos, new Object()devido à possibilidade de algo substituir a função Objeto, você também deve escrever guardas em todo o lugar quando usa ajudantes Object.keyspara garantir que não sejam indefinidos, o que diminui o absurdo. Eu sempre recomendaria que as pessoas usassem a notação literal, mas acho que esse argumento em particular se desfaz quando você pensa nas consequências de pensar dessa maneira.
22418 philraj
41

Na minha máquina usando o Node.js, 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 que esta é uma extensão do que é encontrado aqui: Por que arr = [] é mais rápido que arr = new Array?

minha saída foi a seguinte:

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

tão claramente {} e [] são mais rápidos que usar new para criar objetos / matrizes vazios.

rjloura
fonte
3
Eu sinto que esta é a resposta que a pergunta estava realmente procurando, embora eu gostaria de ter visto isso adicionalmente testado em um objeto com algumas propriedades para garantir.
precisa
2
Números interessantes. Há pessoas que precisam estar cientes disso, mas retiro que alocar até 200.000 objetos apenas me custará 5,6ms, então não vou me preocupar com isso.
No nó 10.13.0 coisas mudaram matriz teste: usando []: 117.178ms usando nova: 116.947ms objeto de teste: usando {}: 116.252ms usando novas: 115.910ms
PirateApp
31

Todo mundo aqui está falando sobre as semelhanças dos dois. Vou apontar as diferenças.

  1. Usar new Object()permite passar outro objeto. O resultado óbvio é que o objeto recém-criado será definido com 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 aos objetos, como nos objetos OOP. Outros tipos também podem ser passados ​​para ele. A função definirá o tipo de acordo. Por exemplo, se passarmos o número 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 em tipo de objeto se uma propriedade fosse adicionada a ele.

    var obj = new Object(1);
    typeof obj // "number"
    obj.a = 2;
    typeof obj // "object"
  4. Se o objeto for uma cópia de uma classe filho 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
Jermin Bazazian
fonte
3
Eu estou muito confuso sobre as duas últimas linhas .. Porque se você atribuir a str.a o valor 1, str.a é indefinido .. @Jermin Bazazin?
Andrea Scarafoni
3
@AndreaScarafoni porque stré do tipo, stringportanto você não pode atribuir uma propriedade a ele. jsfiddle.net/grq6hdx7/1
Chris Bier
1
A resposta para 4 mudou? Fico falso, não é verdade, no Chrome 53 mais recente var obj = new Object("foo"); typeof obj; obj === "foo" // true
William Hilton
21

Na verdade, existem várias maneiras de criar objetos em JavaScript. Quando você deseja apenas criar um objeto, não há benefício em criar objetos " baseados em construtores " usando o operador " novo ". É o mesmo que criar um objeto usando a sintaxe " literal de objeto ". Mas os objetos " baseados em construtores " criados com o operador " novo " são de uso incrível quando você pensa em " herança prototípica ". Você não pode manter a cadeia de herança com objetos criados com sintaxe literal. Mas você pode criar uma função de construtor , anexar propriedades e métodos ao seu protótipo."operador, ele 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 a função construtora (consulte 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 de construção Person e todos eles herdarão fullname () dela.

Nota: a palavra-chave " this " se refere a um objeto vazio dentro de uma função construtora e sempre que você cria um novo objeto a partir de Person usando o operador " new ", ele retorna automaticamente um objeto que contém todas as propriedades e métodos anexados à palavra-chave " this " . E esses objetos certamente herdarão os métodos e propriedades anexados ao protótipo da função construtora Person (que é a principal vantagem dessa abordagem).

A propósito, se você deseja obter a mesma funcionalidade com sintaxe " literal de objeto ", 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 devo usar a abordagem da função construtora em vez da abordagem literal do objeto :

*** 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 de funções do construtor. Caso contrário, você teria que copiá-los repetidamente em todos os objetos.

Espero que isto faça sentido.

Md. Zubaer Ahammed
fonte
Obrigado! Karl por adicionar o "this" ausente no literal do objeto. Foi um erro horrível ... Eu não deveria ter cometido esse tipo de erro.
Md. Zubaer Ahammed
"Você não pode herdar de um objeto criado com sintaxe literal." - Não é verdade (eu acredito). Você pode usar Object.create(<object defined using literal notation>)ou new Object(<object defined using literal notation>)criar cadeias de herança, conforme necessário.
balajeerc
Obrigado por seu comentário. Na verdade, deve ser "Você não pode manter a cadeia de herança com objetos criados com sintaxe literal". O respondente está em várias etapas: 1. Object.create (): Sim, é possível passar um objeto literal para ele e ele retornará um novo objeto cujo protótipo será esse objeto passado literalmente. Mas ele não sabe o que é a função construtora ou não se lembra do objeto literal a partir do qual foi criado. Portanto, testobj1.constructor retornará uma função vazia e não haverá como adicionar propriedades / métodos a esse objeto literal como pai / ancestral.
Md. Zubaer Ahammed
@balajeerc 2. new Object (): Quase a mesma coisa acontece neste caso. Além disso, é pior se você pensar em memória. Em vez de colocar as propriedades e métodos em seu protótipo, ele apenas copia tudo do literal do objeto passado e o coloca no objeto retornado. Não é bom para a memória. Por outro lado, concentrei-me na verdadeira cadeia de herança com uma função construtora na qual é possível editar métodos e propriedades dinamicamente e outros objetos criados usando o método construtor também são afetados, pois apontam apenas para essa função construtora (em vez de copiá-los) .
Md. Zubaer Ahammed
@balajeerc Exemplo: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

Além disso, de acordo com alguns dos livros de javascript O'Really .... (citado)

Outro motivo para usar literais em oposição ao 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 intérprete precisa procurar a cadeia de escopos do local que você está chamando Object () até encontrar o construtor global Object.

adolfo_isassi
fonte
24
espera O'Really era um erro de digitação ou um trocadilho deliberado? Eles deveriam usar isso para divulgar seus livros!
Tim Ogilvy
3

Eu encontrei uma diferença, para ES6 / ES2015. Você não pode retornar um objeto usando a sintaxe da função de seta abreviada, a menos que o rodeie 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 } ]

Isso ocorre porque o compilador está confuso {}entre colchetes e pensa que n: ié um rótulo: statement construto de ; o ponto e vírgula é opcional, portanto, não se queixa.

Se você adicionar outra propriedade ao objeto, ele emitirá um erro.

$ 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
fonte
4
Você ainda pode usar uma função de seta, você só precisa de mais chaves e um retorno: [1, 2, 3].map(v => { return {n: v}; });lhe renderá a mesma coisa ...
Heretic Macaco
Claro que você pode usar funções de seta regulares, o que eu estava falando era a versão abreviada, ou seja param => return_value, e a diferença entre usar {}e new Object()neste caso.
Andrei Simionescu
11
Você ainda pode usar a versão abreviada E as funções regulares de seta. Apenas envolva o {n: v} com um par parênteses:[1, 2, 3].map(v => ({n: v}));
Stephen C
1

Atualização de 2019

Executei o mesmo código que @rjloura no meu OSX High Sierra 10.13.6, versão 10.13.0, e estes são os 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
fonte
-2

O uso da memória é diferente se você criar 10 mil instâncias. new Object()manterá apenas uma cópia e {}10 mil cópias.

Richard Miao US
fonte
7
newcria um novo objeto. Ambos levam a mesma quantidade de memória.
Artyer 5/09/17