const product = {
name: 'apple',
category: 'fruits',
price: 1.99
}
console.log(product);Objetos em JavaScript são coleções dinâmicas de pares de valores-chave. A chave é sempre uma string e deve ser exclusiva na coleção. O valor pode ser um primitivo, um objeto ou até uma função.
Podemos acessar uma propriedade usando o ponto ou a notação quadrada.
console.log(product.name);
//"apple"
console.log(product["name"]);
//"apple"Aqui está um exemplo em que o valor é outro objeto.
const product = {
name: 'apple',
category: 'fruits',
price: 1.99,
nutrients : {
carbs: 0.95,
fats: 0.3,
protein: 0.2
}
}O valor do carbs A propriedade é um novo objeto. Aqui está como podemos acessar o carbs propriedade.
console.log(product.nutrients.carbs);
//0.95Nomes de propriedade abreviados
Considere o caso em que temos os valores de nossas propriedades armazenados em variáveis.
const name="apple";
const category = 'fruits';
const price = 1.99;
const product = {
name: name,
category: category,
price: price
}O JavaScript suporta o que é chamado de nomes abreviados de propriedades. Isso nos permite criar um objeto usando apenas o nome da variável. Ele criará uma propriedade com o mesmo nome. O próximo literal de objeto é equivalente ao anterior.
const name="apple";
const category = 'fruits';
const price = 1.99;
const product = {
name,
category,
price
}Object.create
A seguir, vejamos como implementar objetos com comportamento, objetos orientados a objetos.
O JavaScript possui o que é chamado de sistema de protótipo que permite compartilhar o comportamento entre objetos. A idéia principal é criar um objeto chamado protótipo com um comportamento comum e usá-lo ao criar novos objetos.
O sistema de protótipo nos permite criar objetos que herdam o comportamento de outros objetos.
Vamos criar um objeto protótipo que nos permita adicionar produtos e obter o preço total de um carrinho de compras.
const cartPrototype = {
addProduct: function(product){
if(!this.products){
this.products = [product]
} else {
this.products.push(product);
}
},
getTotalPrice: function(){
return this.products.reduce((total, p) => total + p.price, 0);
}
}Observe que desta vez o valor da propriedade addProduct é uma função. Também podemos escrever o objeto anterior usando um formulário mais curto chamado sintaxe do método abreviado.
const cartPrototype = {
addProduct(product){/*code*/},
getTotalPrice(){/*code*/}
}o cartPrototype é o objeto de protótipo que mantém o comportamento comum representado por dois métodos, addProduct e getTotalPrice. Ele pode ser usado para criar outros objetos que herdam esse comportamento.
const cart = Object.create(cartPrototype);
cart.addProduct({name: 'orange', price: 1.25});
cart.addProduct({name: 'lemon', price: 1.75});
console.log(cart.getTotalPrice());
//3o cart objeto tem cartPrototype como seu protótipo. Ele herda o comportamento dele. cart possui uma propriedade oculta que aponta para o objeto de protótipo.
Quando usamos um método em um objeto, esse método é pesquisado primeiro no próprio objeto, e não no seu protótipo.
isto
Observe que estamos usando uma palavra-chave especial chamada this para acessar e modificar os dados no objeto.
Lembre-se de que funções são unidades independentes de comportamento em JavaScript. Eles não são necessariamente parte de um objeto. Quando estão, precisamos ter uma referência que permita que a função acesse outros membros no mesmo objeto. this é o contexto da função. Dá acesso a outras propriedades.
Dados
Você pode se perguntar por que não definimos e inicializamos o products propriedade no próprio objeto protótipo.
Não devemos fazer isso. Protótipos devem ser usados para compartilhar comportamento, não dados. O compartilhamento de dados levará a ter os mesmos produtos em vários objetos do carrinho. Considere o código abaixo:
const cartPrototype = {
products:[],
addProduct: function(product){
this.products.push(product);
},
getTotalPrice: function(){}
}
const cart1 = Object.create(cartPrototype);
cart1.addProduct({name: 'orange', price: 1.25});
cart1.addProduct({name: 'lemon', price: 1.75});
console.log(cart1.getTotalPrice());
//3
const cart2 = Object.create(cartPrototype);
console.log(cart2.getTotalPrice());
//3Tanto o cart1 e cart2 objetos que herdam o comportamento comum do cartPrototype também compartilham os mesmos dados. Nós não queremos isso. Protótipos devem ser usados para compartilhar comportamento, não dados.
Classe
O sistema de protótipo não é uma maneira comum de construir objetos. Os desenvolvedores estão mais familiarizados com a construção de objetos fora das classes.
A sintaxe da classe permite uma maneira mais familiar de criar objetos que compartilham um comportamento comum. Ele ainda cria o mesmo protótipo nos bastidores, mas a sintaxe é mais clara e também evitamos o problema anterior relacionado a dados. A classe oferece um local específico para definir os dados distintos para cada objeto.
Aqui está o mesmo objeto criado usando a sintaxe da classe sugar:
class Cart{
constructor(){
this.products = [];
}
addProduct(product){
this.products.push(product);
}
getTotalPrice(){
return this.products.reduce((total, p) => total + p.price, 0);
}
}
const cart = new Cart();
cart.addProduct({name: 'orange', price: 1.25});
cart.addProduct({name: 'lemon', price: 1.75});
console.log(cart.getTotalPrice());
//3
const cart2 = new Cart();
console.log(cart2.getTotalPrice());
//0Observe que a classe possui um método construtor que inicializou esses dados distintos para cada novo objeto. Os dados no construtor não são compartilhados entre instâncias. Para criar uma nova instância, usamos o new palavra-chave
Eu acho que a sintaxe da classe é mais clara e familiar para a maioria dos desenvolvedores. No entanto, faz uma coisa semelhante, cria um protótipo com todos os métodos e o utiliza para definir novos objetos. O protótipo pode ser acessado com Cart.prototype.
Acontece que o sistema de protótipo é flexível o suficiente para permitir a sintaxe da classe. Portanto, o sistema de classes pode ser simulado usando o sistema de protótipo.
Propriedades Privadas
A única coisa é que o products A propriedade no novo objeto é pública por padrão.
console.log(cart.products);
//[{name: "orange", price: 1.25}
// {name: "lemon", price: 1.75}]Podemos torná-lo privado usando o hash # prefixo.
Propriedades privadas são declaradas com #name sintaxe. # faz parte do próprio nome da propriedade e deve ser usado para declarar e acessar a propriedade. Aqui está um exemplo de declaração products como propriedade privada:
class Cart{
#products
constructor(){
this.#products = [];
}
addProduct(product){
this.#products.push(product);
}
getTotalPrice(){
return this.#products.reduce((total, p) => total + p.price, 0);
}
}
console.log(cart.#products);
//Uncaught SyntaxError: Private field '#products' must be declared in an enclosing classFunções de fábrica
Outra opção é criar objetos como coleções de fechamentos.
Encerramento é a capacidade de uma função acessar variáveis e parâmetros da outra função, mesmo após a execução da função externa. Dê uma olhada no cart objeto construído com o que é chamado de função de fábrica.
function Cart() {
const products = [];
function addProduct(product){
products.push(product);
}
function getTotalPrice(){
return products.reduce((total, p) => total + p.price, 0);
}
return {
addProduct,
getTotalPrice
}
}
const cart = Cart();
cart.addProduct({name: 'orange', price: 1.25});
cart.addProduct({name: 'lemon', price: 1.75});
console.log(cart.getTotalPrice());
//3addProduct e getTotalPrice são duas funções internas acessando a variável products de seus pais. Eles têm acesso ao products evento variável após o pai Cart foi executado. addProduct e getTotalPrice Existem dois fechamentos que compartilham a mesma variável privada.
Cart é uma função de fábrica.
O novo objeto cart criado com a função de fábrica tem o products variável privada. Não pode ser acessado de fora.
console.log(cart.products);
//undefinedAs funções de fábrica não precisam do new palavra-chave, mas você pode usá-lo se quiser. Ele retornará o mesmo objeto, independentemente de você usá-lo ou não.
Recapitular
Normalmente, trabalhamos com dois tipos de objetos, estruturas de dados que possuem dados públicos e nenhum comportamento e objetos orientados a objetos que possuem dados privados e comportamento público.
As estruturas de dados podem ser facilmente construídas usando a sintaxe literal do objeto.
O JavaScript oferece duas maneiras inovadoras de criar objetos orientados a objetos. O primeiro é usar um objeto protótipo para compartilhar o comportamento comum. Objetos herdam de outros objetos. As aulas oferecem uma boa sintaxe de açúcar para criar esses objetos.
A outra opção é definir objetos são coleções de fechamentos.
Para saber mais sobre fechamentos e técnicas de programação de funções, confira minha série de livros Programação Funcional com JavaScript e React.
o Programação Funcional em JavaScript livro está saindo.
