¿Debería usar literales de objeto o funciones de constructor?

94

Me estoy confundiendo sobre de qué manera debería crear un objeto en javascript. Parece que hay al menos dos formas. Uno es usar la notación literal de objeto mientras que el otro usa funciones de construcción. ¿Hay alguna ventaja de uno sobre el otro?

chobo
fuente
1
La mejor respuesta: stackoverflow.com/questions/4597926/… - En resumen, también puede configurar una función para crear instancias en notación literal. Al hacer esto, cada instancia lleva todos los métodos, mientras que con un constructor todas las instancias se refieren a los métodos prototipo. Es decir, el constructor tiene un mejor rendimiento de memoria.
Federico
Si la memoria no es un problema, el acceso a las propiedades de los literales de objetos es mucho más rápido - jsperf.com/module-pattern-vs-object-literal-vs-prototype/4
Daniel Sokolowski

Respuestas:

131

Si no tiene un comportamiento asociado con un objeto (es decir, si el objeto es solo un contenedor de datos / estado), usaría un objeto literal.

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

Aplica el principio KISS . Si no necesita nada más que un simple contenedor de datos, elija un literal simple.

Si desea agregar comportamiento a su objeto, puede ir con un constructor y agregar métodos al objeto durante la construcción o darle a su clase un prototipo.

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;
};

Una clase como esta también actúa como un esquema para su objeto de datos: ahora tiene algún tipo de contrato (a través del constructor) sobre las propiedades que el objeto inicializa / contiene. Un literal gratuito es solo una masa amorfa de datos.

También podría tener una verifyfunción externa que actúe sobre un objeto de datos antiguo simple:

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

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

Sin embargo, esto no es favorable con respecto a la encapsulación: idealmente, todos los datos + comportamiento asociados con una entidad deberían convivir.

Ates Goral
fuente
12
Gran explicación, pero ¿qué hay de poner funciones en un objeto literal? He visto esto antes. En realidad, la publicación a continuación tiene un ejemplo de esto.
Chobo
23
Si incluye las definiciones de función como parte del objeto literal, o usa el this.fn = function ...enfoque en un constructor, cada una de sus instancias de objeto tendrá sus propias copias de funciones. Usando el enfoque de prototipo, adjunta cada función una vez y solo una vez: las instancias las heredarán a través de la herencia de prototipos.
Ates Goral
14
Creo que te perdiste algo importante. solo la función constructora puede proporcionar miembros privados así como miembros públicos (encapsulación). en el objeto literal, todos son públicos.
Royi Namir
¿Cuál sería la mejor forma de hacerlo para un motor de juego? Usé el método del constructor pero mis prototipos no tienen acceso a los datos del constructor.
zachdyer
90

Básicamente, se reduce a si necesita varias instancias de su objeto o no; El objeto definido con un constructor le permite tener varias instancias de ese objeto. Los literales de objeto son básicamente singleton con variables / métodos que son todos públicos.

// 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
fuente
1
Este es un buen punto a tener en cuenta a la hora de decidir. Gracias.
zkent
En mi experiencia, esto es exactamente lo que marca la diferencia. Gran ejemplo claro.
aire
9

Otra forma de crear objetos de manera uniforme es usar una función que devuelva un objeto:

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!

Dado que las funciones en JavaScript son cierres, podemos usar variables y métodos privados y evitar new.

De http://javascript.crockford.com/private.html sobre variables privadas en JavaScript.

JustcallmeDrago
fuente
7

El código siguiente muestra tres métodos para crear un objeto, sintaxis literal de objeto, un constructor de funciones y Object.create(). La sintaxis literal de objeto simplemente crea un objeto sobre la marcha y, como tal, __prototype__es el Objectobjeto y tendrá acceso a todas las propiedades y métodos de Object. Estrictamente desde la perspectiva de un patrón de diseño, se debe usar un literal de objeto simple para almacenar una única instancia de datos.

El constructor de funciones tiene una propiedad especial llamada .prototype. Esta propiedad se convertirá en la propiedad __prototype__de cualquier objeto creado por el constructor de la función. Todas las propiedades y métodos agregados a la .prototypepropiedad de un constructor de funciones estarán disponibles para todos los objetos que crea. Se debe usar un constructor si necesita múltiples instancias de los datos o requiere el comportamiento de su objeto. Tenga en cuenta que el constructor de funciones también se utiliza mejor cuando desea simular un patrón de desarrollo público / privado. Recuerde poner todos los métodos compartidos en el .prototypepara que no se creen en cada instancia de objeto.

La creación de objetos con Object.create()utiliza un objeto literal como __prototype__para los objetos creados por este método. Todas las propiedades y métodos agregados al objeto literal estarán disponibles para todos los objetos creados a partir de él a través de una verdadera herencia de prototipos. Este es mi método preferido.

//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
fuente
1
Dado que declaró la función dentro de un objeto literal. ¿Eso significa que cuando crea un objeto usando Object.createla función dentro del literal será único por instancia?
JohnnyQ
6

Depende de lo que quieras hacer. Si desea utilizar variables o funciones (semi) privadas en su objeto, una función de constructor es la forma de hacerlo. Si su objeto solo contiene propiedades y métodos, un objeto literal está bien.

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

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

Ahora el método multiply5en myObjy SomeLiteralhacer exactamente lo mismo. La única diferencia es que myObj usa una variable privada. Este último puede resultar útil en algunos casos. La mayoría de las veces, un objeto literal es suficiente y una forma agradable y limpia de crear un objeto JS.

KooiInc
fuente
¿Cuál es la diferencia entre una función y un método? Vengo de ac # background, así que para mí una función es independiente y un método es solo una función que es parte de una clase.
Chobo
1
No hay mucha diferencia, consulte, por ejemplo, web-source.net/javascript_tutorial/… . En realidad, en DOMscripting (js del lado del cliente en un navegador), todas las funciones se convierten en métodos del objeto de ventana (el espacio de nombres global), diría (puede abordar todas las funciones 'independientes' como ventana. [Alguna función].
KooiInc
5

ingrese la descripción de la imagen aquí

¿Quiere una sola instancia del objeto para la página? Literal.

¿Desea simplemente transferir datos como objetos DTO simple GET SET: - Literal

¿Quieres crear objetos reales con comportamientos de métodos, múltiples instancias? - Función de constructor, Seguir los principios de OOP, herencia: - Funciones de constructor.

A continuación se muestra el video de youtube que explica en detalle qué es literal, qué son las funciones del constructor y en qué se diferencian entre sí.

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

Shivprasad Koirala
fuente
1

Vaya con el objeto literal, es más coherente y se expande mejor con la introducción de valores iniciales.

Tom
fuente
¿Cómo se crean variables privadas en un objeto literal?
EhevuTov
Realmente no puedes, no es relevante para la pregunta original, así que solo te daré un enlace: javascript.crockford.com/private.html
Tom
1
En realidad, es relevante porque donde hay una diferencia, hay una razón para usar uno u otro dependiendo de determinadas situaciones; en este caso, sería si desea variables privadas o no. Puede crear variables privadas en un literal creando primero una función de cierre en su literal, pero es mucho más feo en mi opinión y difícil de leer.
EhevuTov
Estoy corregido, mi lectura original de la pregunta fue que chobo preguntaba cómo pasar variables a un constructor como en la lista de parámetros frente al parámetro literal de un solo objeto.
Tom
1

Como se menciona en https://www.w3schools.com/js/js_object_definition.asp

Usando un objeto literal, ambos definen y crean , un objeto en una declaración.

también

El literal de objeto solo crea un único objeto. A veces nos gusta tener un tipo de objeto que se pueda usar para crear muchos objetos de un tipo.

Alireza Fattahi
fuente
0

En realidad, creo que podemos tener métodos privados en literales de objeto. Considere el código a continuación:

var myObject = {

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

}

Es una cuestión de gusto, pero prefiero usar literales de objeto donde sea posible.

yurin
fuente
-1

// Literal de objeto y constructor de objeto

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
fuente
1
¿Dónde en su ejemplo se declara el objeto literal?
JohnnyQ