Quelle est la différence entre «new Object ()» et la notation littérale d'objet?

199

Quelle est la différence entre cette syntaxe basée sur le constructeur pour créer un objet:

person = new Object()

... et cette syntaxe littérale:

person = {
    property1 : "Hello"
};

Il semble que les deux font la même chose, bien que JSLint préfère que vous utilisiez la notation littérale d'objet.

Laquelle est la meilleure et pourquoi?

ectype
la source
7
Tout de même: a = new Object, a = new Object(), a = {}, littéral est beaucoup plus simple et quelques tests j'ai couru un certain temps dire il y a il est plus rapide, les compilateurs plus récents peuvent avoir fait ma déclaration fausse. La même chose s'applique aux tableaux littéraux
Juan Mendes
8
J'espère que vous déclarez vos variables avec le varmot - clé dans votre code d'application pour éviter de polluer l'espace de noms global et de créer la nécessité de regarder au-delà de l'enregistrement en cours dans la pile pour vos variables.
Samo
1
Fondamentalement, à tout moment pendant l'exécution d'un programme, il y a une pile d'enregistrements ou de blocs. Chaque enregistrement a une liste de variables qui ont été créées dans cette étendue. En JavaScript, si une expression contient une variable et que l'interpréteur ne peut pas la trouver dans l'enregistrement de pile pour cette étendue, il continuera jusqu'à l'enregistrement suivant jusqu'à ce qu'il trouve la variable. Plus d'infos davidshariff.com/blog/…
Samo
2
Éviter JSLint est la première étape pour devenir un bon développeur. L'usage newest une convention qui transcende la sélection inutile d'un langage médiocre. À utiliser newcar sa signification est claire. Dans 99,9% des cas, les gains de performance ne sont pas pertinents.
Hal50000
1
@ Hal50000 langue médiocre selon qui?
Xam

Réponses:

124

Ils font tous les deux la même chose (sauf si quelqu'un a fait quelque chose d'inhabituel), à part que votre deuxième crée un objet et lui ajoute une propriété. Mais la notation littérale prend moins de place dans le code source. Il est clairement reconnaissable de ce qui se passe, donc en utilisant new Object(), vous tapez vraiment plus et (en théorie, s'il n'est pas optimisé par le moteur JavaScript), vous effectuez un appel de fonction inutile.

Celles-ci

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

person = {
    property1 : "Hello"
};

techniquement ne font pas la même chose. Le premier crée juste un objet. Le second en crée un et attribue une propriété. Pour que la première soit la même, vous avez alors besoin d'une deuxième étape pour créer et affecter la propriété.

Le "quelque chose d'inhabituel" que quelqu'un pourrait faire serait de suivre ou d'assigner au Objectglobal par défaut :

// Don't do this
Object = 23;

Dans ce cas très inhabituel , new Objectéchouera mais {}fonctionnera.

En pratique, il n'y a jamais de raison d'utiliser new Objectplutôt que {}(sauf si vous avez fait cette chose très inhabituelle).

kemiller2002
la source
11
L'auteur a choisi cette réponse comme correcte, mais elle est incomplète. Soyez conscient qu'il existe des différences entre les deux syntaxes lorsque vous entrez dans l'allocation de mémoire.
newshorts
2
Il n'y a aucune différence. Si vous faites référence à l'une des réponses ci-dessous, elle est hors sujet, car elle parle de modèle d'objet basé sur un prototype et d'héritage (le code y configure une classe Obj qui hérite de Object simple). Cette question ne concerne pas la création d'une instance d'une classe personnalisée - elle concerne la création d'une instance d'Object, et la bonne réponse à cette question est "il n'y a pas de différence".
dos
FYI () new Object()n'est pas non plus requis. (en parlant de
machin
Je pense que nous n'avons pas besoin d'utiliser nouveau à partir de la spécification actuelle. Faites-moi part de vos réflexions @kevin
Vamsi Pavan Mahesh
1
Vous pouvez également utiliser Object create et passer null si vous voulez un objet qui n'hérite pas de la chaîne d'héritage. Ils ne sont pas égaux et ont respectivement des objectifs utiles.
Aaron
234

Il n'y a pas de différence pour un objet simple sans méthodes comme dans votre exemple. Cependant, il existe une grande différence lorsque vous commencez à ajouter des méthodes à votre objet.

Voie littérale:

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

Manière de prototype:

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

Les deux façons permettent la création d'instances Objcomme celle-ci:

var foo = new Obj( "hello" ); 

Cependant, avec la méthode littérale, vous transportez une copie de la sayHellométhode dans chaque instance de vos objets. Alors qu'avec la méthode prototype, la méthode est définie dans le prototype d'objet et partagée entre toutes les instances d'objet. Si vous avez beaucoup d'objets ou beaucoup de méthodes, le chemin littéral peut entraîner un gaspillage de mémoire assez important.

Rémy DAVID
la source
39
Pour moi, la question portait davantage sur les différences entre l'utilisation de new Object()vs {}pour créer des objets vides.
Peter
11
@Lobabob Mis à part la première phrase, cette réponse ne fournit en fait aucune information sur la question d'OP. Il ne contient même nulle part "new Object ()". Franchement, je pense que M. David a mal compris la question.
JLRishe
17
Quand j'ai posté cela, la réponse acceptée était déjà là et acceptée. Et cela répond parfaitement à la question OP donc je n'allais pas répéter la même chose. J'ai posté ma réponse principalement pour élargir le sujet au-delà des objets vides / simples. Dans ce cas, il existe une différence importante qui mérite d'être mentionnée.
Rémy DAVID
3
Cette réponse est hors sujet. Dans votre code, Obj est une classe distincte héritant d'Object. Lorsque vous utilisez la notation littérale d'objet, vous utilisez la classe Object, pas Obj. Bien sûr, la mise en place d'une classe avec méthode dans son prototype va réduire l'encombrement de la mémoire plutôt que de créer beaucoup d'objets simples et d'ajouter la méthode comme propriétés, mais cela n'a absolument rien à voir avec la question posée ici. La bonne réponse à cette question est "non, il n'y a absolument aucune différence (peut-être sauf la lisibilité)".
dos
3
Je suis venu pour cette réponse, basée sur une question qui était un peu comme la mienne, mais j'ai fini par apprendre exactement ce que je devais savoir. Je vous remercie.
Pat Migliaccio
55

En JavaScript, nous pouvons déclarer un nouvel objet vide de deux manières:

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

Je n'ai rien trouvé pour suggérer qu'il existe une différence significative entre ces deux en ce qui concerne la façon dont ils fonctionnent en coulisses (veuillez me corriger si je me trompe - j'aimerais savoir). Cependant, la deuxième méthode (utilisant la notation littérale objet) offre quelques avantages.

  1. Il est plus court (10 caractères pour être précis)
  2. Il est plus facile et plus structuré de créer des objets à la volée
  3. Peu importe si un bouffon a outrepassé par inadvertance l'objet

Considérons un nouvel objet qui contient les membres Name et TelNo. En utilisant la nouvelle convention Object (), nous pouvons la créer comme ceci:

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

La fonctionnalité Propriétés Expando de JavaScript nous permet de créer de nouveaux membres de cette façon à la volée, et nous réalisons ce qui était prévu. Cependant, cette façon n'est pas très structurée ou encapsulée. Et si nous voulions spécifier les membres lors de la création, sans avoir à compter sur les propriétés expando et l'affectation post-création?

C'est là que la notation littérale de l'objet peut aider:

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

Ici, nous avons obtenu le même effet dans une ligne de code et beaucoup moins de caractères.

Une autre discussion sur les méthodes de construction d'objets ci-dessus peut être trouvée à: JavaScript et programmation orientée objet (POO).

Et enfin, qu'en est-il de l'idiot qui a dépassé Object? Pensiez-vous que ce n'était pas possible? Eh bien, ce JSFiddle prouve le contraire. L'utilisation de la notation littérale objet nous empêche de tomber dans le piège de cette bouffonnerie.

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

James Wiseman
la source
Si vous préférez les littéraux d'objets en new Object()raison de la possibilité que quelque chose écrase la fonction Objet, vous devriez également écrire des gardes partout lorsque vous utilisez des assistants Object.keysafin de vous assurer qu'elle n'est pas indéfinie, ce qui tombe dans l'absurdité. Je recommanderais toujours aux gens d'utiliser la notation littérale, mais je pense que cet argument particulier s'effondre lorsque vous pensez aux conséquences de penser de cette façon.
philraj
41

Sur ma machine utilisant Node.js, j'ai exécuté ce qui suit:

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

Remarque, ceci est une extension de ce qui se trouve ici: Pourquoi arr = [] est-il plus rapide qu'arr = new Array?

ma sortie était la suivante:

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

il est donc clair que {} et [] sont plus rapides que d'utiliser new pour créer des objets / tableaux vides.

rjloura
la source
3
J'ai l'impression que c'est la réponse que la question cherchait vraiment, bien que j'aurais aimé voir cela en plus testé sur un objet avec quelques propriétés pour être sûr.
Chase Sandmann
2
Des chiffres intéressants. Il y a des gens qui doivent être conscients de cela, mais je retiens qu'allouer même un maigre 200 000 objets ne me coûtera que 5,6 ms, donc je ne vais pas m'en inquiéter.
Sur le noeud 10.13.0, les choses ONT CHANGÉ Tableau de test: en utilisant []: 117.178ms en utilisant nouveau: 116.947ms Objet de test: en utilisant {}: 116.252ms en utilisant nouveau: 115.910ms
PirateApp
31

Tout le monde ici parle des similitudes des deux. Je vais souligner les différences.

  1. L'utilisation new Object()vous permet de passer un autre objet. Le résultat évident est que l'objet nouvellement créé sera défini sur la même référence. Voici un exemple de code:

    var obj1 = new Object();
    obj1.a = 1;
    var obj2 = new Object(obj1);
    obj2.a // 1
  2. L'utilisation n'est pas limitée aux objets comme dans les objets OOP. D'autres types pourraient également lui être transmis. La fonction définira le type en conséquence. Par exemple, si nous lui passons un entier 1, un objet de type numéro sera créé pour nous.

    var obj = new Object(1);
    typeof obj // "number"
  3. L'objet créé à l'aide de la méthode ci-dessus ( new Object(1)) serait converti en type d'objet si une propriété lui était ajoutée.

    var obj = new Object(1);
    typeof obj // "number"
    obj.a = 2;
    typeof obj // "object"
  4. Si l'objet est une copie d'une classe d'objet enfant, nous pourrions ajouter la propriété sans la conversion de type.

    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
la source
3
Je suis très confus au sujet des deux dernières lignes .. Pourquoi si vous attribuez à str.a la valeur 1, str.a n'est pas définie? .. @Jermin Bazazin
Andrea Scarafoni
3
@AndreaScarafoni car strest de type string, vous ne pouvez donc pas lui attribuer de propriété. jsfiddle.net/grq6hdx7/1
Chris Bier
1
La réponse à 4 a-t-elle changé? Je suis faux, pas vrai, dans le dernier Chrome 53 var obj = new Object("foo"); typeof obj; obj === "foo" // true
William Hilton
21

En fait, il existe plusieurs façons de créer des objets en JavaScript. Lorsque vous voulez simplement créer un objet, il n'y a aucun avantage à créer des objets " basés sur un constructeur " à l'aide de l' opérateur " nouveau ". Cela revient à créer un objet à l'aide de la syntaxe " littéral objet ". Mais les objets " basés sur un constructeur " créés avec un " nouvel " opérateur sont incroyablement utiles lorsque vous pensez à "l' héritage prototypique ". Vous ne pouvez pas conserver la chaîne d'héritage avec des objets créés avec une syntaxe littérale. Mais vous pouvez créer une fonction constructeur , attacher des propriétés et des méthodes à son prototype.", il retournera un objet qui aura accès à toutes les méthodes et propriétés attachées au prototype de cette fonction constructeur.

Voici un exemple de création d'un objet à l'aide de la fonction constructeur (voir l'explication du code en bas):

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

Maintenant, vous pouvez créer autant d'objets que vous le souhaitez en instanciant la fonction de construction Personne et tous en hériteront fullname ().

Remarque: " ce " mot clé fera référence à un objet vide dans une fonction constructeur et chaque fois que vous créez un nouvel objet à partir de Personne à l'aide de l' opérateur " nouveau ", il renverra automatiquement un objet contenant toutes les propriétés et méthodes associées au mot clé " ce " . Et ces objets hériteront à coup sûr des méthodes et des propriétés attachées au prototype de la fonction constructeur Person (qui est le principal avantage de cette approche).

Soit dit en passant, si vous souhaitez obtenir la même fonctionnalité avec la syntaxe " littéral objet ", vous devrez créer fullname () sur tous les objets comme ci-dessous:

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

Enfin, si vous demandez maintenant pourquoi devrais-je utiliser l' approche fonction constructeur au lieu de l' approche littérale objet :

*** L'héritage prototypique permet une chaîne d'héritage simple qui peut être extrêmement utile et puissante.

*** Il économise de la mémoire en héritant des méthodes et propriétés communes définies dans le prototype des fonctions constructeur. Sinon, vous devrez les copier encore et encore dans tous les objets.

J'espère que cela a du sens.

Md. Zubaer Ahammed
la source
Merci! Karl pour avoir ajouté le "ceci" manquant dans le littéral de l'objet. C'était une horrible erreur ... Je n'aurais pas dû faire ce type d'erreur.
Md. Zubaer Ahammed
"Vous ne pouvez pas hériter d'un objet créé avec une syntaxe littérale." - Pas vrai (je crois). Vous pouvez utiliser Object.create(<object defined using literal notation>)ou new Object(<object defined using literal notation>)et créer des chaînes d'héritage selon vos besoins.
balajeerc
@balajeerc Merci pour votre commentaire. En fait, cela devrait être "Vous ne pouvez pas maintenir la chaîne d'héritage avec des objets créés avec une syntaxe littérale". La réponse se fait en plusieurs étapes: 1. Object.create (): Oui, il est possible de lui passer un littéral objet et il retournera un nouvel objet dont le prototype sera celui littéral objet passé. Mais il ne sait pas ce qu'est sa fonction constructeur ou ne se souvient pas du littéral objet à partir duquel il a été créé. Ainsi, testobj1.constructor retournera une fonction vide et il n'y aura aucun moyen d'ajouter des propriétés / méthodes à cet objet littéral car il est parent / ancêtre.
Md. Zubaer Ahammed
@balajeerc 2. new Object (): Presque la même chose se produit dans ce cas. De plus, c'est pire si vous pensez à la mémoire. Au lieu de mettre les propriétés et les méthodes dans son prototype, il copie simplement tout du littéral objet passé et le place dans l'objet retourné. Ce n'est pas bon pour la mémoire. D'autre part, je me suis concentré sur la véritable chaîne d'héritage avec une fonction constructeur où vous pouvez modifier les méthodes et les propriétés à la volée et d'autres objets créés à l'aide de la méthode constructeur sont également affectés car ils pointent uniquement sur cette fonction constructeur (au lieu de les copier) .
Md. Zubaer Ahammed
@balajeerc Exemple: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

En outre, selon certains des livres javascript O'Really .... (cité)

Une autre raison d'utiliser des littéraux par opposition au constructeur d'objet est qu'il n'y a pas de résolution de portée. Comme il est possible que vous ayez créé un constructeur local du même nom, l'interpréteur doit rechercher la chaîne de portée depuis l'endroit que vous appelez Object () jusqu'à ce qu'il trouve le constructeur d'objet global.

adolfo_isassi
la source
24
attendez était O'Really une faute de frappe ou un jeu de mots délibéré? Ils devraient l'utiliser pour commercialiser leurs livres!
Tim Ogilvy
3

J'ai trouvé une différence, pour ES6 / ES2015. Vous ne pouvez pas renvoyer un objet à l'aide de la syntaxe de la fonction de flèche raccourcie, sauf si vous entourez l'objet avec 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 } ]

En effet, le compilateur est confondu par les {}crochets et pense qu'il n: is'agit d'une construction label: statement ; le point-virgule est facultatif, il ne s'en plaint donc pas.

Si vous ajoutez une autre propriété à l'objet, il générera finalement une erreur.

$ 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
la source
4
Vous pouvez toujours utiliser une fonction de flèche, vous avez juste besoin de plus d'accolades et d'un retour: [1, 2, 3].map(v => { return {n: v}; });vous rapportera la même chose ...
Heretic Monkey
Bien sûr, vous pouvez utiliser les fonctions de flèche régulières, ce dont je parlais était la version abrégée, c'est param => return_value-à- dire la différence entre l'utilisation {}et new Object()dans ce cas.
Andrei Simionescu
11
Vous pouvez toujours utiliser la version abrégée ET les fonctions de flèche régulières. Enveloppez simplement le {n: v} avec une paire de parenthèses:[1, 2, 3].map(v => ({n: v}));
Stephen C
1

Mise à jour 2019

J'ai exécuté le même code que @rjloura sur mon noeud OSX High Sierra 10.13.6 version 10.13.0 et voici les résultats

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
la source
-2

L'utilisation de la mémoire est différente si vous créez 10 000 instances. new Object()ne gardera qu'une seule copie tandis que {}gardera 10 mille copies.

Richard Miao US
la source
7
newcrée un nouvel objet. Ils prennent tous deux la même quantité de mémoire.
Artyer