Qual o melhor caminho para criar um objeto em JavaScript? O `var` é necessário antes da propriedade de um objeto?


177

Até agora, vi três maneiras de criar um objeto em JavaScript. Qual o melhor caminho para criar um objeto e por quê?

Também vi que em todos esses exemplos a palavra var- chave não é usada antes de uma propriedade - por quê? Não é necessário declarar varantes do nome de uma propriedade, pois mencionou que propriedades são variáveis?

Na segunda e na terceira maneira, o nome do objeto está em letras maiúsculas, enquanto, na primeira maneira, o nome do objeto está em letras minúsculas. Que caso devemos usar para o nome de um objeto?

Primeira maneira:

function person(fname, lname, age, eyecolor){
  this.firstname = fname;
  this.lastname = lname;
  this.age = age;
  this.eyecolor = eyecolor;
}

myFather = new person("John", "Doe", 50, "blue");
document.write(myFather.firstname + " is " + myFather.age + " years old.");

Segunda maneira:

var Robot = {
  metal: "Titanium",
  killAllHumans: function(){
    alert("Exterminate!");
  }
};

Robot.killAllHumans();

Terceira maneira - objetos JavaScript usando sintaxe de matriz:

var NewObject = {};

NewObject['property1'] = value;
NewObject['property2'] = value;
NewObject['method'] = function(){ /* function code here */ }

2
o "var" é usado dependendo do escopo da variável, define o global ou não, pesquise e você verá a diferença.
jackJoe

80
se você criar robôs homicidas, utilize sempre var, por favor .. omitindo que os torna mundial
mykhal

9
"var é usado dependendo do escopo da variável" - esta é uma má prática - ele deve ser usado não importa o escopo você está em
treecoder

1
E o método Object.create():?
Max

Seria bom se "como mencionado que propriedades são variáveis" fosse esclarecido. Quem é esse"? Onde isso é mencionado? Você pode citar uma cotação específica?
user4642212

Respostas:


181

Não há melhor maneira, depende do seu caso de uso.

  • Use o modo 1 se desejar criar vários objetos semelhantes. No seu exemplo, Person(você deve iniciar o nome com uma letra maiúscula) é chamada de função construtora . Isso é semelhante às classes em outros idiomas OO.
  • Use o modo 2 se você precisar apenas de um objeto do tipo (como um singleton). Se você deseja que esse objeto seja herdado de outro, é necessário usar uma função construtora.
  • Use a maneira 3 se desejar inicializar propriedades do objeto dependendo de outras propriedades ou se tiver nomes de propriedades dinâmicos.

Atualização: Como exemplos solicitados pela terceira maneira.

Propriedades dependentes:

O seguinte não funciona como thisnão se refere book. Não há como inicializar uma propriedade com valores de outras propriedades em um literal de objeto:

var book = {
    price: somePrice * discount,
    pages: 500,
    pricePerPage: this.price / this.pages
};

em vez disso, você pode fazer:

var book = {
    price: somePrice * discount,
    pages: 500
};
book.pricePerPage = book.price / book.pages;
// or book['pricePerPage'] = book.price / book.pages;

Nomes de propriedades dinâmicas:

Se o nome da propriedade estiver armazenado em alguma variável ou criado por meio de alguma expressão, você precisará usar a notação de colchete:

var name = 'propertyName';

// the property will be `name`, not `propertyName`
var obj = {
    name: 42
}; 

// same here
obj.name = 42;

// this works, it will set `propertyName`
obj[name] = 42;

1
obrigado pela sua resposta ... agora que entendi seu primeiro ponto, podemos usar o caminho1 se quisermos algo como isto myFather = new person ("John", "Doe", 50, "blue"); myMother = nova pessoa ("gazy", "Doe", 45, "marrom"); myBrother = nova pessoa ("poll", "Doe", 15, "blue");
28911 Jamna

Eu acho que você quer dizer obj [name] = 42. Certo?
Keith Pinson

Gostaria de salientar que as opções 2 e 3 são praticamente idênticas, apenas que você está atribuindo propriedades depois de criar o objeto. Isso é chamado de notação literal , porque você está usando um literal de objeto para criar seu objeto. Sob o capô, isso realmente chama "new Object ()". Você pode ler mais sobre isso aqui: developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/…
dudewad

Para o segundo caso, faria sentido se usássemos o operador de propagação ...para herdar de outro objeto?
6pack garoto

114

Há várias maneiras de definir uma função. É totalmente baseado em sua exigência. Abaixo estão alguns estilos: -

  1. Construtor de Objetos
  2. Construtor literal
  3. Baseado em funções
  4. Baseado em Protoype
  5. Baseado em Função e Protótipo
  6. Baseado em Singleton

Exemplos:

  1. Construtor de objetos
var person = new Object();

person.name = "Anand",
person.getName = function(){
  return this.name ; 
};
  1. Construtor literal
var person = { 
  name : "Anand",
  getName : function (){
   return this.name
  } 
} 
  1. construtor da função
function Person(name){
  this.name = name
  this.getName = function(){
    return this.name
  } 
} 
  1. Protótipo
function Person(){};

Person.prototype.name = "Anand";
  1. Combinação de função / protótipo
function Person(name){
  this.name = name;
} 
Person.prototype.getName = function(){
  return this.name
} 
  1. Singleton
var person = new function(){
  this.name = "Anand"
} 

Você pode experimentá-lo no console, se tiver alguma confusão.


HEy @Alex_Nabu - Eu já compartilhei os exemplos no meu post. Se você ainda enfrentar algum problema, atualize-me.
Anand Deep Singh

1
não faria mais sentido criar todos os exemplos que produzam exatamente a mesma var personinstância no final? por exemplo, no construtor de funções, você pode simplesmente adicionar var person = new Person("Anand"). e o que há com o uso aparentemente aleatório de ponto e vírgula? : P
cregox

2
Acrescentaria valor explicando os prós e contras de cada caminho.
RayLoveless

10

Não há "melhor maneira" de criar um objeto. Cada maneira tem benefícios, dependendo do seu caso de uso.

O padrão do construtor (uma função emparelhada com o newoperador para invocá-lo) fornece a possibilidade de usar herança prototípica, enquanto as outras formas não. Portanto, se você deseja uma herança prototípica, uma função construtora é um bom caminho a percorrer.

No entanto, se você deseja uma herança prototípica, use também o Object.createque torna a herança mais óbvia.

Criar um literal de objeto (ex:) var obj = {foo: "bar"};funciona muito bem se você tiver todas as propriedades que deseja definir em mãos no momento da criação.

Para definir propriedades posteriormente, a NewObject.property1sintaxe geralmente é preferível NewObject['property1']se você souber o nome da propriedade. Mas o último é útil quando você não tem o nome da propriedade antes do tempo (ex:) NewObject[someStringVar].

Espero que isto ajude!


6

Eu acho que depende do que você quer. Para objetos simples, acho que você poderia usar os segundos métodos. Quando seus objetos crescem e você planeja usar objetos semelhantes, acho que o primeiro método seria melhor. Dessa forma, você também pode estendê-lo usando protótipos.

Exemplo:

function Circle(radius) {
    this.radius = radius;
}
Circle.prototype.getCircumference = function() {
    return Math.PI * 2 * this.radius;
};
Circle.prototype.getArea = function() {
    return Math.PI * this.radius * this.radius;
}

Não sou muito fã do terceiro método, mas é realmente útil para editar propriedades dinamicamente, por exemplo var foo='bar'; var bar = someObject[foo];.


3

Existem várias maneiras de criar seus objetos em JavaScript. O uso de uma função construtora para criar um objeto ou notação literal de objeto está usando muito em JavaScript. Também criando uma instância do Object e adicionando propriedades e métodos a ela, existem três maneiras comuns de criar objetos em JavaScript.

Funções construtoras

Existem funções construtoras incorporadas que todos nós podemos usá-las periodicamente, como Date (), Number (), Boolean () etc, todas as funções construtoras começam com letra maiúscula, enquanto isso, podemos criar uma função construtora personalizada em JavaScript como isso:

function Box (Width, Height, fill) {  
  this.width = Width;  // The width of the box 
  this.height = Height;  // The height of the box 
  this.fill = true;  // Is it filled or not?
}  

e você pode invocá-lo, simplesmente usando new (), para criar uma nova instância do construtor, criar algo como abaixo e chamar a função construtora com parâmetros preenchidos:

var newBox = new Box(8, 12, true);  

Literais de objeto

O uso de literais de objeto é um caso muito usado para criar objetos em JavaScript; este é um exemplo de criação de um objeto simples; você pode atribuir qualquer coisa às suas propriedades, desde que definidas:

var person = { 
    name: "Alireza",
    surname: "Dezfoolian"
    nose: 1,  
    feet: 2,  
    hands: 2,
    cash: null
};  

Prototipagem

Depois de criar um Objeto, você pode criar um protótipo de mais membros, por exemplo, adicionando cores à nossa Caixa, podemos fazer isso:

Box.prototype.colour = 'red';

2

Embora muitas pessoas aqui digam que não há melhor maneira de criar objetos, há uma justificativa para o motivo de haver tantas maneiras de criar objetos em JavaScript, a partir de 2019, e isso tem a ver com o progresso do JavaScript nas diferentes iterações dos lançamentos EcmaScript desde 1997.

Antes do ECMAScript 5, havia apenas duas maneiras de criar objetos: a função construtora ou a notação literal (uma alternativa melhor ao novo Object ()). Com a notação da função construtora, você cria um objeto que pode ser instanciado em várias instâncias (com a nova palavra-chave), enquanto a notação literal entrega um único objeto, como um singleton.

// constructor function
function Person() {};

// literal notation
var Person = {};

Independentemente do método usado, os objetos JavaScript são simplesmente propriedades de pares de valores-chave:

// Method 1: dot notation
obj.firstName = 'Bob';

// Method 2: bracket notation. With bracket notation, you can use invalid characters for a javascript identifier.
obj['lastName'] = 'Smith';

// Method 3: Object.defineProperty
Object.defineProperty(obj, 'firstName', {
    value: 'Bob',
    writable: true,
    configurable: true,
    enumerable: false
})

// Method 4: Object.defineProperties
Object.defineProperties(obj, {
  firstName: {
    value: 'Bob',
    writable: true
  },
  lastName: {
    value: 'Smith',
    writable: false
  }
});

Nas versões anteriores do JavaScript, a única maneira real de imitar a herança baseada em classes era usar funções de construtor. a função construtora é uma função especial que é chamada com a palavra-chave 'new'. Por convenção, o identificador da função é maiúsculo, embora não seja necessário. Dentro do construtor, nos referimos à palavra-chave 'this' para adicionar propriedades ao objeto que a função construtora está criando implicitamente. A função construtora retorna implicitamente o novo objeto com as propriedades preenchidas de volta à função de chamada implicitamente, a menos que você use explicitamente a palavra-chave return e retorne outra coisa.

function Person(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;

    this.sayName = function(){
        return "My name is " + this.firstName + " " + this.lastName;
    }
} 

var bob = new Person("Bob", "Smith");
bob instanceOf Person // true

Há um problema com o método sayName. Normalmente, nas linguagens de programação baseadas em classes orientadas a objetos, você usa classes como fábricas para criar objetos. Cada objeto terá suas próprias variáveis ​​de instância, mas terá um ponteiro para os métodos definidos no blueprint da classe. Infelizmente, ao usar a função construtora do JavaScript, toda vez que é chamada, ela define uma nova propriedade sayName no objeto recém-criado. Portanto, cada objeto terá sua própria propriedade sayName exclusiva. Isso consumirá mais recursos de memória.

Além do aumento dos recursos de memória, a definição de métodos dentro da função do construtor elimina a possibilidade de herança. Novamente, o método será definido como uma propriedade no objeto recém-criado e em nenhum outro objeto; portanto, a herança não pode funcionar como. Portanto, o JavaScript fornece a cadeia de protótipos como uma forma de herança, tornando o JavaScript uma linguagem prototípica.

Se você tem um pai e um pai compartilha muitas propriedades de um filho, ele deve herdar essas propriedades. Antes do ES5, era realizado da seguinte maneira:

function Parent(eyeColor, hairColor) {
    this.eyeColor = eyeColor;
    this.hairColor = hairColor;
}

Parent.prototype.getEyeColor = function() {
  console.log('has ' + this.eyeColor);
}

Parent.prototype.getHairColor = function() {
  console.log('has ' + this.hairColor);
}

function Child(firstName, lastName) {
  Parent.call(this, arguments[2], arguments[3]);
  this.firstName = firstName;
  this.lastName = lastName;
}

Child.prototype = Parent.prototype;

var child = new Child('Bob', 'Smith', 'blue', 'blonde');
child.getEyeColor(); // has blue eyes
child.getHairColor(); // has blonde hair

A maneira como utilizamos a cadeia de protótipos acima tem uma peculiaridade. Como o protótipo é um link ativo, alterando a propriedade de um objeto na cadeia de protótipos, você também alteraria a mesma propriedade de outro objeto. Obviamente, alterar o método herdado de uma criança não deve alterar o método dos pais. O Object.create resolveu esse problema usando um polyfill. Assim, com Object.create, você pode modificar com segurança a propriedade de uma criança na cadeia de protótipos sem afetar a mesma propriedade do pai na cadeia de protótipos.

O ECMAScript 5 introduziu o Object.create para resolver o erro mencionado anteriormente na função construtora para criação de objetos. O método Object.create () cria um novo objeto, usando um objeto existente como o protótipo do objeto recém-criado. Como um novo objeto é criado, você não tem mais o problema de que a modificação da propriedade filho na cadeia de protótipos modificará a referência do pai para essa propriedade na cadeia.

var bobSmith = {
    firstName: "Bob",
    lastName: "Smith",
    sayName: function(){
      return "My name is " + this.firstName + " " + this.lastName;
    }
}

var janeSmith = Object.create(bobSmith, {
    firstName : {  value: "Jane" }
})

console.log(bobSmith.sayName()); // My name is Bob Smith
console.log(janeSmith.sayName()); // My name is Jane Smith
janeSmith.__proto__ == bobSmith; // true
janeSmith instanceof bobSmith; // Uncaught TypeError: Right-hand side of 'instanceof' is not callable. Error occurs because bobSmith is not a constructor function.

Antes do ES6, havia um padrão criacional comum para utilizar construtores de funções e Object.create:

const View = function(element){
  this.element = element;
}

View.prototype = {
  getElement: function(){
    this.element
  }
}

const SubView = function(element){
  View.call(this, element);
}

SubView.prototype = Object.create(View.prototype);

Agora Object.create, juntamente com funções de construtor, têm sido amplamente utilizados para criação e herança de objetos em JavaScript. No entanto, o ES6 introduziu o conceito de classes, que são principalmente açúcar sintático sobre a herança baseada em protótipo existente do JavaScript. A sintaxe da classe não introduz um novo modelo de herança orientada a objetos ao JavaScript. Assim, o JavaScript continua sendo uma linguagem prototípica.

As classes ES6 tornam a herança muito mais fácil. Não precisamos mais copiar manualmente as funções de protótipo da classe pai e redefinir o construtor da classe filha.

// create parent class
class Person {
  constructor (name) {
    this.name = name;
  }
}

// create child class and extend our parent class
class Boy extends Person {
  constructor (name, color) {
    // invoke our parent constructor function passing in any required parameters
    super(name);

    this.favoriteColor = color;
  }
}

const boy = new Boy('bob', 'blue')
boy.favoriteColor; // blue

Ao todo, essas 5 estratégias diferentes de Criação de Objetos em JavaScript coincidiram com a evolução do padrão EcmaScript.


0

É claro que existe uma maneira melhor. Os objetos em javascript têm propriedades enumeráveis ​​e não enumeráveis.

var empty = {};
console.log(empty.toString);
// . function toString(){...}
console.log(empty.toString());
// . [object Object]

No exemplo acima, você pode ver que um objeto vazio realmente possui propriedades.

Ok, primeiro vamos ver qual é a melhor maneira:

var new_object = Object.create(null)

new_object.name = 'Roland'
new_object.last_name = 'Doda'
//etc

console.log("toString" in new_object) //=> false

No exemplo acima, o log produzirá false.

Agora vamos ver por que as outras formas de criação de objetos estão incorretas.

//Object constructor
var object = new Object();

console.log("toString" in object); //=> true

//Literal constructor
var person = { 
  name : "Anand",
  getName : function (){
   return this.name
  } 
} 

console.log("toString" in person); //=> true

//function Constructor
function Person(name){
  this.name = name
  this.getName = function(){
    return this.name
  } 
}

var person = new Person ('landi')

console.log("toString" in person); //=> true

//Prototype
function Person(){};

Person.prototype.name = "Anand";

console.log("toString" in person); //=> true

//Function/Prototype combination
function Person2(name){
  this.name = name;
} 

Person2.prototype.getName = function(){
  return this.name
}

var person2 = new Person2('Roland')

console.log("toString" in person2) //=> true

Como você pode ver acima, todos os exemplos são verdadeiros. O que significa que, se você tiver um caso, um for inloop para ver se o objeto tem uma propriedade provavelmente levará a resultados errados.

Observe que a melhor maneira não é fácil. Você precisa definir todas as propriedades do objeto linha por linha. As outras maneiras são mais fáceis e terão menos código para criar um objeto, mas você deve estar ciente em alguns casos. Eu sempre uso as "outras maneiras" a propósito e uma solução para o aviso acima se você não usar a melhor maneira é:

 for (var property in new_object) {
  if (new_object.hasOwnProperty(property)) {
    // ... this is an own property
  }
 }

0

Principalmente, existem três maneiras de criar objetos -

O mais simples é usar literais de objetos .

const myObject = {}

Embora este método seja o mais simples, mas tenha uma desvantagem, ou seja, se o seu objeto tiver comportamento (funciona nele), no futuro, se você quiser fazer alguma alteração, precisará alterá-lo em todos os objetos .

Portanto, nesse caso, é melhor usar as funções de fábrica ou de construtor (qualquer pessoa que você gosta)

Funções de fábrica são aquelas funções que retornam um objeto.

function factoryFunc(exampleValue){
   return{
      exampleProperty: exampleValue 
   }
}

Funções de construtor são aquelas funções que atribuem propriedades a objetos usando a palavra-chave "this".

function constructorFunc(exampleValue){
   this.exampleProperty= exampleValue;
}
const myObj= new constructorFunc(1);
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.