Devo usar literais de objeto ou funções de construtor?

94

Estou ficando confuso sobre como devo criar um objeto em javascript. Parece que existem pelo menos duas maneiras. Uma é usar notação literal de objeto enquanto a outra usa funções de construção. Existe uma vantagem de um sobre o outro?

chobo
fonte
1
A melhor resposta: stackoverflow.com/questions/4597926/… - Em resumo, você pode configurar uma função para criar instâncias de notação literal também. Fazendo isso, cada instância carrega todos os métodos, enquanto com um construtor todas as instâncias se referem aos métodos de protótipo. Ou seja, o construtor tem melhor desempenho de memória.
Federico
Se a memória não for um problema, o acesso à propriedade de literais de objeto é muito mais rápido - jsperf.com/module-pattern-vs-object-literal-vs-prototype/4
Daniel Sokolowski

Respostas:

131

Se você não tiver um comportamento associado a um objeto (ou seja, se o objeto for apenas um contêiner de dados / estado), eu usaria um literal de objeto.

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

Aplique o princípio KISS . Se você não precisa de nada além de um simples contêiner de dados, use um literal simples.

Se você deseja adicionar comportamento ao seu objeto, você pode ir com um construtor e adicionar métodos ao objeto durante a construção ou dar a sua classe um protótipo.

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

Uma classe como essa também atua como um esquema para seu objeto de dados: agora você tem algum tipo de contrato (por meio do construtor) de quais propriedades o objeto inicializa / contém. Um literal livre é apenas uma bolha amorfa de dados.

Você também pode ter uma verifyfunção externa que atua em um objeto de dados simples e antigo:

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

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

No entanto, isso não é favorável com relação ao encapsulamento: Idealmente, todos os dados + comportamento associados a uma entidade devem viver juntos.

Ates Goral
fonte
12
Ótima explicação, mas que tal colocar funções em um literal de objeto? Eu já vi isso ser feito antes. Na verdade o post abaixo tem um exemplo disso.
chobo de
23
Se você incluir as definições de função como parte do literal do objeto ou usar a this.fn = function ...abordagem em um construtor, cada uma das instâncias de seu objeto terá suas próprias cópias de funções. Usando a abordagem de protótipo, você anexa cada função uma vez e apenas uma vez: elas serão herdadas pelas instâncias por meio da herança prototípica.
Ates Goral
14
Eu acredito que você perdeu uma coisa importante. apenas a função de construtor pode fornecer membros privados, bem como membros públicos (encapsulamento). no literal do objeto - eles são todos públicos.
Royi Namir de
Qual seria a melhor maneira de obter um motor de jogo? Usei o método do construtor, mas meus protótipos não têm acesso aos dados do construtor.
zachdyer
90

Basicamente, ele se resume a se você precisa ou não de várias instâncias do seu objeto; objeto definido com um construtor permite que você tenha várias instâncias desse objeto. Literais de objeto são basicamente singletons com variáveis ​​/ métodos que são 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
fonte
1
Este é um ponto muito bom para se ter em mente ao decidir. THX.
zkent
Na minha experiência, é exatamente isso que faz a diferença. Ótimo exemplo claro.
Air
9

Outra maneira de criar objetos de maneira uniforme é usar uma função que retorna um 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!

Uma vez que as funções em JavaScript são encerramentos, podemos usar variáveis ​​e métodos privados e evitar new.

De http://javascript.crockford.com/private.html em variáveis ​​privadas em JavaScript.

JustcallmeDrago
fonte
7

O código abaixo mostra três métodos de criação de um objeto, sintaxe Object Literal, um Construtor de Função e Object.create(). A sintaxe literal do objeto simplesmente cria um objeto em tempo real e, como tal, __prototype__é o Objectobjeto e terá acesso a todas as propriedades e métodos deObject . Estritamente de uma perspectiva de padrão de projeto, um literal de objeto simples deve ser usado para armazenar uma única instância de dados.

O construtor da função tem uma propriedade especial chamada .prototype. Esta propriedade se tornará a __prototype__de qualquer objeto criado pelo construtor da função. Todas as propriedades e métodos adicionados à .prototypepropriedade de um construtor de função estarão disponíveis para todos os objetos que ele cria. Um construtor deve ser usado se você precisar de várias instâncias dos dados ou de comportamento do seu objeto. Observe que o construtor de função também é melhor usado quando você deseja simular um padrão de desenvolvimento privado / público. Lembre-se de colocar todos os métodos compartilhados no .prototypepara que não sejam criados em cada instância do objeto.

A criação de objetos com Object.create()utiliza um literal de objeto __prototype__para os objetos criados por este método. Todas as propriedades e métodos adicionados ao literal do objeto estarão disponíveis para todos os objetos criados a partir dele por meio da verdadeira herança prototípica. Este é o meu 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
fonte
1
Desde que você declarou a função dentro de um literal de objeto. Isso significa que quando você cria um objeto usando Object.createa função dentro do literal, ele será exclusivo por instância?
JohnnyQ
6

Depende do que você quer fazer. Se você quiser usar variáveis ​​ou funções (semi-) privadas em seu objeto, uma função construtora é a maneira de fazê-lo. Se o seu objeto contém apenas propriedades e métodos, um literal de objeto é adequado.

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

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

Agora o método multiply5entra myObje SomeLiteralfaz exatamente a mesma coisa. A única diferença é que myObj usa uma variável privada. O último pode ser útil em alguns casos. Na maioria das vezes, um literal de objeto é suficiente e uma maneira limpa e agradável de criar um objeto JS.

KooiInc
fonte
Qual é a diferença entre uma função e um método? Eu venho de um background c #, então para mim uma função é autônoma e um método é apenas uma função que faz parte de uma classe.
chobo
1
Não há muita diferença, veja por exemplo web-source.net/javascript_tutorial/… . Na verdade, em DOMscripting (client side js em um navegador), todas as funções se tornam métodos do objeto de janela (o namespace global), eu diria (você pode endereçar todas as funções 'autônomas' como janela. [Alguma função].
KooiInc
5

insira a descrição da imagem aqui

Você quer uma instância única do objeto para a página - Literal.

Você quer apenas transferir dados como objetos DTO simples GET SET: - Literal

Você deseja criar objetos reais com comportamentos de método, múltiplas instâncias - Função de construtor, Siga os princípios OOP, herança: - Funções de construtor.

Abaixo está o vídeo do youtube que explica em detalhes o que é literal, o que são funções construtoras e como elas diferem umas das outras.

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

Shivprasad Koirala
fonte
1

Vá com o literal de objeto, é mais consistente e se expande melhor com a introdução de valores iniciais.

Tom
fonte
Como você cria variáveis ​​privadas em um literal de objeto?
EhevuTov
Você não pode realmente, não é relevante para a pergunta original, então vou apenas dar-lhe um link: javascript.crockford.com/private.html
Tom,
1
Na verdade, é relevante porque onde há diferença, há razão para usar um ou outro dependendo de certas situações; neste caso, seria se você deseja variáveis ​​privadas ou não. Você pode criar variáveis ​​privadas em um literal criando primeiro uma função de fechamento em seu literal, mas é muito mais feio na minha opinião e difícil de ler.
EhevuTov
Estou corrigido, minha leitura original da questão era que chobo estava perguntando sobre como passar variáveis ​​para um construtor como na lista de parâmetros vs parâmetro literal de objeto único.
Tom,
1

Conforme mencionado em https://www.w3schools.com/js/js_object_definition.asp

Usando um literal de objeto, você define e cria , um objeto em uma instrução.

Além disso

O literal de objeto cria apenas um único objeto. Às vezes, gostamos de ter um tipo de objeto que pode ser usado para criar muitos objetos de um tipo.

Alireza Fattahi
fonte
0

A função construtora Object () é um pouco mais lenta e detalhada. Como tal, a maneira recomendada de criar novos objetos em JavaScript é usar notação literal

JavaScript orientado a objetos Udacity

Techkuz
fonte
0

Na verdade, acho que podemos ter métodos privados em literais de objeto. Considere o código abaixo:

var myObject = {

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

}

É questão de gosto, mas prefiro usar literais de objeto onde for possível.

Yurin
fonte
-1

// Object Literal e Object constructor

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
fonte
1
Onde em seu exemplo o literal Object é declarado?
JohnnyQ