Desenvolvimento

18 abr, 2018

Programação orientada a objetos em JavaScript

2884 visualizações
Publicidade

E aí pessoal, tudo bom? Quero compartilhar uma coisa bem legal com vocês aqui.

Nós sabemos que o JavaScript é uma linguagem fracamente tipada, ou seja, as variáveis não precisam ter um tipo definido assim que nós as declaramos, e também podemos mudar o tipo que é armazenado nas mesmas em tempo de execução. Porém, existem maneiras de usarmos a Orientação a Objetos no JavaScript. Mas primeiro vamos definir, de fato, o que é POO (Programação Orientada a Objetos).

Conceito de POO

O objetivo de todo programador é criar soluções que aumentem a produtividade ou facilitem a vida dos usuários, portanto, devemos sempre buscar resolver problemas da vida real, como a automatização do registro de um fluxo de caixa, controlar quais carros entram e saem de um estacionamento, o horário dos ônibus de uma cidade, etc.

Logo, tratamos no código, coisas que existem no mundo “real”.

The Matrix (1999)

As coisas normalmente tem propriedades. Um animal, por exemplo, tem uma espécie (cachorro, gato, pato), um som característico (“Au au”, “miau”, “quack”), um nome (“Rex”, “Fifi”, “Donald”) e uma idade. Esse mesmo animal, que tem um som característico às vezes emite o som característico que lhe é atribuído.

Agora imagine que para cada um desses três animais que eu listei, nós tivéssemos que declarar variáveis, funções e saber, o tempo todo, como cada coisa funciona. Acaba sobrecarregando a cabeça da gente, né? Também temos que considerar que, normalmente, trabalhamos em equipes, e talvez eu tenha que usar o que outra pessoa codificou. Na verdade, isso é quase uma certeza.

Então a POO aumenta o grau de abstração do programador. Tá, a primeira vez que ouvi essa frase eu fiquei pensando: “Ãhn? O que está acontecendo?”. Mas apesar da frase em um primeiro momento parecer assustadora, a informação contida nela é bem simples.

O Programador vai ter que se preocupar menos em como as coisas funcionam por dentro, depois que houver modelado as classes e interfaces. Temos, assim, uma visão muito mais parecida com a que temos aqui “fora”. Existem outras vantagens em se fazer uma modelagem e estrutura de código legais.

Posso colocar a questão do reaproveitamento de código. Não há motivo para codificar sempre a mesma coisa, é perder tempo e aplicar esforço onde não é necessário. Reusar o código deve ser uma preocupação de qualquer programador. Se você, ou outra pessoa, consegue reusar um código que você criou, isso quer dizer que você fez um bom trabalho! A maior dica que já me deram, é:

Faça com que suas funções executem somente uma coisa, mas que o façam bem feito!

“O reuso de código é o Santo Graal da Engenharia de Software”

Classes

Uma classe é a estrutura que abstrai um determinado conjunto de características, chamadas de atributos, ações e chamadas de métodos.

Em JavaScript usamos o identificador class para declarar uma classe, seguido pelo nome da classe, com a primeira letra em caixa alta (por convenção).

Objetos

Nossa, até que enfim chegamos nos objetos, né? A programação é orientada a objetos e eu não falei deles ainda.

Objetos são instâncias das classes. Falando dos animais, imagine que você tem um gato e um cachorro. Ambos derivam da classe animal, porém, cada um tem suas características e são seres diferentes. Portanto, cada um seria uma instância da classe animal, entende? Bom, chega de falar e vamos ao código.

“Falar é fácil. Me mostre o código” — Linus Torvalds (tradução adaptada)

Vamos primeiro declarar a classe Animal:

class Animal {
  constructor(type, name, sound, age) {
    this.type = type;
    this.name = name;
    this.sound = sound;
    this.age = age;
  }
  makeASound() {
    console.log(`${this.name} says: ${this.sound}`);
  }
}

No exemplo, temos o identificador class e o nome da classe com a primeira letra em caixa alta, como eu havia dito. Logo após, temos o constructor, que é um conceito que precisa ser entendido por todos que trabalham com Orientação a Objetos.

O método construtor, é o método que será executado no momento da criação de uma instância daquela classe, ou seja, no momento da criação de um objeto. Ele é um conjunto de instruções que deve ser executada a fim de preparar o objeto para ser usado. O método construtor pode, ou não, receber atributos. No nosso caso, o método recebe todos os atributos do animal que será criado.

Tenho também o identificador this, que simplificando bastante, trata dos atributos inerentes somente ao objeto manipulado naquele momento. Em um artigo posterior falarei um pouco mais sobre o escopo de variáveis em JavaScript.

E por último, mas não menos importante, declaro a função makeASound, que exibirá na tela uma mensagem mostrando o atributo nome e o som que o animal produz.

Instanciando objetos

Agora já declarei uma classe, lembrando que, diferentemente das funções que são hoisted – isso quer dizer que a você pode usar uma função antes de declara-lá no código, o JavaScript se encarregará de levar a declaração ao topo -, as classes obrigatoriamente devem ser declaradas antes de serem usadas.

Para criar um objeto, usamos o identificador new, seguido pelo nome da classe e passamos parâmetros para o construtor, se necessário. Vamos ver isso.

var pudim = new Animal('cat', 'Pudim', 'meauou', 3);
var misty = new Animal('dog', 'Misty', 'Au Au Au', 1);
var vaca = new Animal();

Acima, por três vezes, eu declaro uma variável e atribuo um objeto recém instanciado a ela. Vamos deixar de lado os nomes que eu escolhi, meus bichos têm nomes diferentes mesmo. Reparem que nas variáveis misty e vaca, eu passei ao construtor todos os atributos possíveis, portanto, todas as variáveis tratadas por ele serão atribuídas de forma correta.

Mas na variável vaca eu escolhi não passar nenhum atributo, ou seja, todas os atributos deste objeto estarão como undefined. Claro que, normalmente, nós devemos criar métodos getters e setters para as propriedades de uma classe, a fim de manipularmos estes atributos após a criação dos objetos. Mas o momento de falar sobre isso não é este, só preciso que vocês saibam que isto não é imutável.

Por fim, vamos mostrar como estes objetos estão, e como a função makeASound é executada.

console.log(pudim); 
// Output:
// Animal { type: 'cat', name: 'Pudim', sound: 'meauou', age: 3 }

console.log(misty);
// Output:
// Animal{ type: 'dog', name: 'Misty', sound: 'Au Au Au', age: 1 }

console.log(vaca);
// Output:
// Animal {
//  type: undefined,
//  name: undefined,
//  sound: undefined,
//  age: undefined }

pudim.makeASound();
// Output: Pudim says: meauou

misty.makeASound();
// Output: Misty says: Au Au Au

vaca.makeASound();
// Output: undefined says: undefined

Acima, podemos ver os atributos de cada um dos objetos instanciados, assim como a execução do método que declarei na classe Animal, aumentando o grau de abstração do programador que usará esta classe, assim como o reaproveitamento de código, pois não precisei declarar várias vezes as propriedades e métodos para cada “variável” que usei daquele tipo. Bem legal, né?

Essa foi uma introdução sobre orientação a objetos. Em breve publicarei artigos falando sobre herança, sobrescrita e algumas outras coisas legais pra ajudar vocês a dominarem esse paradigma de programação.

Há um link para esse projeto, já funcionando no GitHub. Você pode acessá-lo clicando aqui.

Para mais dicas sobre JavaScript e Node.js, se inscreva no meu canal do YouTube. Sempre tem vídeos novos.

Espero que tenha ajudado. Um abraço!