A orientação a objetos é uma velha conhecida dos desenvolvedores e está presente na grande maioria das linguagens de programação, tais como PHP, Java e JavaScript. Conhecer o conceito de orientação a objetos está comumente associado à sua linguagem de programação do dia a dia, ou à primeira linguagem em que você a utilizou.
Uma vez que se conhece esse conceito e se passa a aprender uma nova linguagem também orientada a objetos, os conhecimentos adquiridos previamente facilitam a transição para a nova linguagem, bem como carregamos conosco o conhecimento de instruções condicionais, laços e variáveis. No entanto, quando se trata de orientação a objetos em JavaScript, nem sempre a transição e compreensão são tão simples quanto gostaríamos.
Primeiro, porque a sua característica dinâmica e fracamente tipada permitem mais liberdade na construção de estruturas de dados, objetos e valores das variáveis, ou seja, não há uma restrição que force o desenvolvedor a seguir um certo padrão de programação. Essa liberdade exige maior atenção e, principalmente, disciplina do desenvolvedor.
Outro fator marcante é que, diferente da maioria das linguagens, o JavaScript é uma linguagem orientada a objetos baseada em protótipos e não em classes como as linguagens mais populares.
A programação baseada em protótipos é um estilo de programação orientada a objetos no qual o comportamento de reuso (também conhecido como herança) é aplicado através da clonagem de objetos existentes, que servem como protótipos.
Usemos como exemplo
um objeto animal, que possui todas as características e
comportamentos de um animal, tais como tamanho, peso, andar e comer. Com a
clonagem desse objeto poderíamos dar origem ao objeto mamifero,
que herdaria todas as características e comportamentos do objeto animal e
agregaria suas próprias características particulares, tais como olhos, patas,
amamentar e mamar.
A partir daí cada cachorro, por exemplo, seria um novo clone do objeto mamifero.
Para entender bem como funciona a orientação a objetos no JavaScript, você precisa dominar, além dos protótipos, a função call() e compreender porque as funções são consideradas “cidadãs de primeira classe” no JavaScript.
É claro que se dominar outros aspectos da linguagem poderá tirar vantagem da combinação desses três pontos base com outros recursos, explorando ainda mais o potencial do JavaScript.
A importância das funções
Por ser uma linguagem de script feita para ser simples, o JavaScript faz uso das funções para diferentes propósitos, desde o seu uso tradicional até construtores de protótipos.
Um aspecto fundamental da linguagem é a utilização de funções para diversos propósitos, que vão muito além de meras funções que recebem argumentos e executam um trecho de código. Por terem essa característica “multiuso” as funções são chamadas de cidadãos de primeira classe da linguagem JavaScript.
Vejamos alguns exemplos:
· Funções são usadas para definir um protótipo e serem instanciadas posteriormente através da palavra-chave new, como veremos mais adiante.
· Funções podem ser auto executáveis, podendo utilizar valores locais, porém dentro de um contexto volátil, como podemos ver em IIFE (Immediately Invoked Function Expressions).
· Funções podem ser passadas como argumentos para outras funções.
· Em JavaScript funções são objetos, portanto, possuem outras funções e atributos, como por exemplo toString(), call(), apply(), length, name.
· Funções podem ser declaradas e executadas dentro de outras funções.
Apenas com os exemplos citados é possível perceber que, diferentemente de outras linguagens, as funções desempenham um papel bastante especial no JavaScript e é por essa razão que devemos dar a devida atenção a elas. E para nos aprofundar ainda mais nesse universo vamos falar um pouco mais sobre a importante função call().
A função call()
A função call de uma função (lembre-se: em JavaScript as funções possuem funções) oferece um novo objeto “this” como seu objeto principal, dando-lhe assim um novo contexto. Quando chamamos a função call() de uma determinada função estamos dizendo que ela deve utilizar o contexto de outro objeto this, ao invés de usar o seu objeto original, do qual ela faz parte ou que foi instanciado a partir de um protótipo. Em outras palavras, é como se tivéssemos um objeto A e um objeto B, cada qual com suas propriedades e métodos.
Digamos então que o objeto A possui os atributos valorBase, taxa e desconto e um método chamado calcular(), que faz um cálculo envolvendo os três atributos do mesmo. Para chamarmos esse método usaríamos A.calcular(), porém o objeto B possui os mesmos três atributos e com os mesmos nomes daqueles do objeto A, mas não possui o método calcular().
Com a função call() aplicada ao método calcular do objeto A é possível executá-la utilizando o contexto do objeto B. Ou seja, a partir da instância do objeto A podemos executar o método calcular e “pegar emprestado” os valores do objeto B para realizar o cálculo, como é demonstrado na Listagem 1.
Listagem 1. Exemplo de uso da função call.