Dois-je utiliser des littéraux d'objet ou des fonctions de constructeur?

94

Je suis confus sur la manière dont je devrais créer un objet en javascript. Il semble qu'il y ait au moins deux façons. L'une consiste à utiliser la notation littérale d'objet tandis que l'autre utilise des fonctions de construction. Y a-t-il un avantage de l'un sur l'autre?

chobo
la source
1
La meilleure réponse: stackoverflow.com/questions/4597926/… - En résumé, vous pouvez également configurer une fonction pour créer des instances sous forme de notation littérale. En faisant cela, chaque instance transporte toutes les méthodes, alors qu'avec un constructeur, toutes les instances font référence aux méthodes prototypes. Ie constructeur a de meilleures performances de mémoire.
Federico
Si la mémoire n'est pas un problème, l'accès aux propriétés des objets littéraux est beaucoup plus rapide - jsperf.com/module-pattern-vs-object-literal-vs-prototype/4
Daniel Sokolowski

Réponses:

131

Si vous n'avez pas de comportement associé à un objet (c'est-à-dire si l'objet n'est qu'un conteneur de données / état), j'utiliserais un littéral d'objet.

var data = {
    foo: 42,
    bar: 43
};

Appliquez le principe KISS . Si vous n'avez besoin de rien d'autre qu'un simple conteneur de données, optez pour un simple littéral.

Si vous souhaitez ajouter un comportement à votre objet, vous pouvez utiliser un constructeur et ajouter des méthodes à l'objet pendant la construction ou donner à votre classe un prototype.

function MyData(foo, bar) {
    this.foo = foo;
    this.bar = bar;

    this.verify = function () {
        return this.foo === this.bar;
    };
}

// or:
MyData.prototype.verify = function () {
    return this.foo === this.bar;
};

Une classe comme celle-ci agit également comme un schéma pour votre objet de données: vous avez maintenant une sorte de contrat (via le constructeur) quelles propriétés l'objet initialise / contient. Un littéral gratuit est juste une goutte amorphe de données.

Vous pourriez aussi bien avoir une verifyfonction externe qui agit sur un ancien objet de données:

var data = {
    foo: 42,
    bar: 43
};

function verify(data) {
    return data.foo === data.bar;
}

Cependant, cela n'est pas favorable en ce qui concerne l'encapsulation: idéalement, toutes les données + comportement associé à une entité devraient cohabiter.

Ates Goral
la source
12
Excellente explication, mais qu'en est-il de mettre des fonctions dans un objet littéral? J'ai déjà vu cela se faire. En fait, l'article ci-dessous en a un exemple.
chobo
23
Si vous incluez les définitions de fonction dans le cadre du littéral d'objet ou si vous utilisez l' this.fn = function ...approche dans un constructeur, chacune de vos instances d'objet aura ses propres copies de fonctions. En utilisant l'approche prototype, vous attachez chaque fonction une et une seule fois: elles seront héritées par les instances via l'héritage prototypique.
Ates Goral
14
Je crois que vous avez manqué une chose importante. seule la fonction constructeur peut fournir des membres privés ainsi que des membres publics (encapsulation). dans l'objet littéral - ils sont tous publics.
Royi Namir
Quelle serait la meilleure façon d'utiliser un moteur de jeu? J'ai utilisé la méthode du constructeur mais mes prototypes n'ont pas accès aux données du constructeur.
zachdyer
90

Cela revient essentiellement à savoir si vous avez besoin de plusieurs instances de votre objet ou non; objet défini avec un constructeur vous permet d'avoir plusieurs instances de cet objet. Les littéraux d'objet sont essentiellement des singletons avec des variables / méthodes qui sont toutes publiques.

// define the objects:
var objLit = {
  x: 0,
  y: 0,
  z: 0,
  add: function () {
    return this.x + this.y + this.z;
  }
};

var ObjCon = function(_x, _y, _z) {
  var x = _x; // private
  var y = _y; // private
  this.z = _z; // public
  this.add = function () {
    return x + y + this.z; // note x, y doesn't need this.
  };
};

// use the objects:
objLit.x = 3; 
objLit.y = 2; 
objLit.z = 1; 
console.log(objLit.add());    

var objConIntance = new ObjCon(5,4,3); // instantiate an objCon
console.log(objConIntance.add());
console.log((new ObjCon(7,8,9)).add()); // another instance of objCon
console.log(objConIntance.add()); // same result, not affected by previous line
Ronnbot
la source
1
C'est un très bon point à garder à l'esprit au moment de prendre une décision. THX.
zkent
D'après mon expérience, c'est exactement ce qui fait la différence. Excellent exemple clair.
Air
9

Une autre façon de créer des objets de manière uniforme consiste à utiliser une fonction qui renvoie un objet:

function makeObject() {
    var that = {
        thisIsPublic: "a public variable"
        thisIsAlsoPublic: function () {
            alert(that.thisIsPublic);
        }
    };

    var secret = "this is a private variable"

    function secretFunction() { // private method
        secret += "!"; // can manipulate private variables
        that.thisIsPublic = "foo";     
    }

    that.publicMethod = function () {
        secret += "?"; // this method can also mess with private variables
    }

    that.anotherPublicVariable = "baz";

    return that; // this is the object we've constructed
}

makeObject.static = "This can be used to add a static varaible/method";

var bar = makeObject();
bar.publicMethod(); // ok
alert(bar.thisIsPublic); // ok
bar.secretFunction(); // error!
bar.secret // error!

Puisque les fonctions en JavaScript sont des fermetures, nous pouvons utiliser des variables et des méthodes privées et éviter new.

De http://javascript.crockford.com/private.html sur les variables privées en JavaScript.

JustcallmeDrago
la source
7

Le code ci-dessous montre trois méthodes de création d'un objet, la syntaxe Object Literal, un constructeur de fonction et Object.create(). La syntaxe littérale d'objet crée simplement un objet à la volée et en tant que tel, __prototype__c'est l' Objectobjet et il aura accès à toutes les propriétés et méthodes deObject . Du point de vue du modèle de conception, un simple littéral Object doit être utilisé pour stocker une seule instance de données.

Le constructeur de fonction a une propriété spéciale nommée .prototype. Cette propriété deviendra la __prototype__de tous les objets créés par le constructeur de fonction. Toutes les propriétés et méthodes ajoutées à la .prototypepropriété d'un constructeur de fonction seront disponibles pour tous les objets qu'il crée. Un constructeur doit être utilisé si vous avez besoin de plusieurs instances des données ou si vous avez besoin d'un comportement de votre objet. Notez que le constructeur de fonction est également mieux utilisé lorsque vous souhaitez simuler un modèle de développement privé / public. N'oubliez pas de mettre toutes les méthodes partagées sur le .prototypeafin qu'elles ne soient pas créées dans chaque instance d'objet.

La création d'objets avec Object.create()utilise un objet littéral comme __prototype__pour les objets créés par cette méthode. Toutes les propriétés et méthodes ajoutées au littéral d'objet seront disponibles pour tous les objets créés à partir de celui-ci via un véritable héritage prototypique. C'est ma méthode préférée.

//Object Example

//Simple Object Literal
var mySimpleObj = {
    prop1 : "value",
    prop2 : "value"
}

// Function Constructor
function PersonObjConstr()  {
    var privateProp = "this is private";
    this.firstname = "John";
    this.lastname = "Doe";
}
PersonObjConstr.prototype.greetFullName = function()    {
    return "PersonObjConstr says: Hello " + this.firstname + 
    " " + this.lastname;
};

// Object Literal
var personObjLit = {
    firstname : "John",
    lastname: "Doe",
    greetFullName : function() {
        return "personObjLit says: Hello " + this.firstname +
        ", " + this.lastname;
    }
} 

var newVar = mySimpleObj.prop1;
var newName = new PersonObjConstr();
var newName2 = Object.create(personObjLit);
JOP
la source
1
Puisque vous avez déclaré la fonction dans un objet littéral. Cela signifie-t-il que lorsque vous créez un objet à Object.createl' aide de la fonction à l'intérieur du littéral, il sera unique par instance?
JohnnyQ
6

Cela dépend de ce que vous voulez faire. Si vous souhaitez utiliser des variables ou des fonctions (semi-) privées dans votre objet, une fonction constructeur est le moyen de le faire. Si votre objet ne contient que des propriétés et des méthodes, un littéral d'objet convient.

function SomeConstructor(){
    var x = 5;
    this.multiply5 = function(i){
        return x*i;
    }
}
var myObj = new SomeConstructor;

var SomeLiteral = {
    multiply5: function(i){ return i*5; }
}

Maintenant , la méthode multiply5dans myObjet SomeLiteralfaire exactement la même chose. La seule différence est que myObj utilise une variable privée. Ce dernier peut être utile dans certains cas. La plupart du temps, un littéral Object est suffisant et constitue une manière agréable et propre de créer un objet JS.

KooiInc
la source
Quelle est la différence entre une fonction et une méthode? Je viens du fond ac # donc pour moi une fonction est autonome et une méthode est juste une fonction qui fait partie d'une classe.
chobo
1
Il n'y a pas beaucoup de différence, voir par exemple web-source.net/javascript_tutorial/... . En fait, dans DOMscripting (js côté client dans un navigateur), toutes les fonctions deviennent des méthodes de l'objet window (l'espace de noms global) je dirais (vous pouvez adresser toutes les fonctions 'autonomes' comme window. [Somefunction].
KooiInc
5

entrez la description de l'image ici

Voulez-vous une seule instance de l'objet pour la page - Littéral.

Voulez-vous simplement transférer des données comme des objets DTO simples GET SET: - Literal

Voulez-vous créer des objets réels avec des comportements de méthode, plusieurs instances - Fonction constructeur, Suivez les principes de la POO, héritage: - Fonctions constructeur.

Vous trouverez ci-dessous la vidéo youtube qui explique en détail ce qui est littéral, ce que sont les fonctions du constructeur et en quoi elles diffèrent les unes des autres.

https://www.youtube.com/watch?v=dVoAq2D3n44

Shivprasad Koirala
la source
1

Allez avec un objet littéral, c'est plus consise et se développe mieux avec l'introduction de valeurs initiales.

À M
la source
Comment créer des variables privées dans un objet littéral?
EhevuTov
Vous ne pouvez pas vraiment, ce n'est pas pertinent par rapport à la question d'origine, donc je vais juste vous donner un lien: javascript.crockford.com/private.html
Tom
1
En fait, c'est pertinent parce que là où il y a une différence, il y a une raison d'utiliser l'un ou l'autre selon certaines situations; dans ce cas, il s'agirait de savoir si vous voulez ou non des variables privées. Vous pouvez créer des variables privées dans un littéral en créant d'abord une fonction de fermeture dans votre littéral, mais c'est beaucoup plus laid à mon avis et difficile à lire.
EhevuTov
Je suis corrigé, ma lecture originale de la question était que chobo demandait comment passer des variables à un constructeur comme dans la liste de paramètres par rapport au paramètre littéral d'objet unique.
Tom
1

Comme mentionné dans https://www.w3schools.com/js/js_object_definition.asp

L' utilisation d' un littéral d'objet, vous aussi bien définir et créer , un objet dans une déclaration.

Aussi

Object littéral ne crée qu'un seul objet. Parfois, nous aimons avoir un type d'objet qui peut être utilisé pour créer de nombreux objets d'un même type.

Alireza Fattahi
la source
0

La fonction constructeur Object () est un peu plus lente et plus détaillée. En tant que tel, la méthode recommandée pour créer de nouveaux objets en JavaScript est d'utiliser la notation littérale

JavaScript orienté objet Udacity

techkuz
la source
0

En fait, je pense que nous pouvons avoir des méthodes privées dans les littéraux d'objet. Considérez le code ci-dessous:

var myObject = {

   publicMethod: function () {
      privateMethod1();
      privateMethod2(); 
      function privateMethod1(){
          console.log('i am privateMethod1');
      } 
      function privateMethod2(){
          console.log('i am privateMethod2');
      } 
   }

}

Question de goût, mais je préfère utiliser des objets littéraux là où c'est possible.

yurin
la source
-1

// Object Literal et Object constructeur

function MyData(foo, bar) {
        this.foo = foo;
        this.bar = bar;

    }
MyData.prototype.verify = function () {
        return this.foo === this.bar;
    };

//add property using prototype

var MD  = new MyData;//true.
var MD = new MyData();//true.
MD.verify// return only the function structure.
MD.verify(); //return the verify value and in this case return true coz both value is null. 
var MD1  = new MyData(1,2); // intialized the value at the starting. 
MD1.verify// return only the function structure.
MD1.verify(); // return false coz both value are not same.
MD1.verify(3,3);// return false coz this will not check this value intialized at the top 
MyData.prototype.verify = function (foo,bar) {
    return this.foo === this.bar;
};
var MD1  = new MyData(1,2);
MD1.verify();
MD1.verify(3,3);// return false coz this keyword used with foo and bar that will check parent data 
Amit Kumar
la source
1
Où, dans votre exemple, le littéral Object est-il déclaré?
JohnnyQ