"Toda reforma interior e toda mudança para melhor dependem exclusivamente da aplicação do nosso próprio esforço." - Immanuel Kant

Anteriormente, vimos Como Dominar Javascript "this" com 3 exemplos. Agora iremos ver 3 maneiras de mudar seu valor, conforme nossa necessidade.

A habilidade de usar e manipular o valor que this assume em funções é essencial para boa programação orientada a objetos em JavaScript. Funções podem ser utilizadas em diferentes contextos e temos que ser capazes de trabalhar com elas em cada situação.

Normalmente this é automaticamente atribuído, mas você pode alterar seu valor por várias razões(reaproveitamento de código, por exemplo), conforme veremos nos exemplos a seguir.

Existem 3 métodos de função capazes de alterar o valor this: Call, Apply e Bind. Por método de função queremos dizer que toda função em JavaScript possui nativamente implementada essas 3 propriedades. O mecanismo de herança que permite isso acontecer será visto muito em breve quando apresentarmos os prototypes.

Call

Este é o primeiro método de funções capaz de alterar o valor this. O primeiro parâmetro que recebe é o valor de this que que será atribuído à função. Os demais parâmetros são os parâmetros da função que invoca o método Call. Vejamos:

function sayThis(n1,n2){  
    console.log(this * n1 * n2);
}
// 2 é this, n1 e n2 são 3
sayThis.call(2, 3, 3) // 18  
// 1 é this, n1 e n2 são 3
sayThis.call(1, 3, 3) // 9  

A lógica do funcionamento está clara acima, mas o legal mesmo é utilizá-la para reaproveitamento de código. Vejamos outro exemplo bem simples que dará essa idéia:

function sayAnyCharacter() {  
    console.log(this.name + ": " + this.character);
};
var actor1 = {  
    name:"Clint Eastwood",
    character: "The Good"
};
var actor2 = {  
    name:"Lee Van Cleef",
    character: "The Bad"
};
// Clint Eastwood: The Good
sayAnyCharacter.call(actor1);  
// Lee Van Cleef: The Bad
sayAnyCharacter.call(actor2);  

Estrutura de dados são dados sem comportamento.
Função é comportamento sem dados.
Objetos são dados com comportamento(métodos).

O exemplo acima mostra uma capacidade interessante do JavaScript, ele é capaz de separar totalmente os dados do comportamento e ainda assim facilmente torná-los simultaneamente úteis pelo poder de combiná-los. Imagine que você tivesse um arquivo de dados JSON. A demonstração acima mostra que seria facilmente possível, através do método call, transformar dados em objetos ao conferir aos primeiros um comportamento desejado. Essa capacidade é uma das coisas que torna JavaScript tão interessante.

Reaproveitando métodos nativos

Em nosso artigo Saiba Tudo Sobre Callbacks, nos deparamos com a seguinte situação: filtrar elementos input DOM que possuíam determinada característica.

Lá explicamos que os inputs retornados pelo seguinte trecho de código var inputs = document.getElementsByTagName("input"); possuem a mesma estrutura de arrays, mas não possuem o método filter no qual estamos realmente interessados.

Sabemos que se inputs fosse realmente array tudo estaria resolvido. Mas existe uma segunda alternativa. Podemos aproveitar a estrutura do filter dos arrays, modificando apenas o objeto(this) que sofrerá a ação do método. E foi exatamente o que fizemos ao criar a função filterDomElements:

function filterDomElements(elements, filterCallback) {  
        return Array.prototype.filter.call(elements, filterCallback);   
}

Ou ainda:

function filterDomElements(elements, filterCallback) {  
        return [].filter.call(elements, filterCallback);    
}

Apply

Apply é o segundo método de funções capaz de alterar o valor this. Ele funciona exatamente como o método Call, porém seu segundo parâmetro recebe um Array ou Array-like dos parâmetros da função. Vejamos o mesmo primeiro exemplo apresentado aqui, mas agora utilizando o apply:

function sayThis(n1,n2){  
    console.log(this * n1 * n2);
}
// 2 é this, n1 e n2 são 3
sayThis.apply(2, [3, 3]) // 18  
// 1 é this, n1 e n2 são 3
sayThis.apply(1, [3, 3]) // 9  

O método apply é especialmente útil para se trabalhar com o Arguments Object (ver O poder das Javascript Functions).

Douglas Crockford em uma de suas palestras propôs o seguinte exercício: "Escreva uma função que recebe uma outra função como parâmetro e a retorna de forma que ela só possa ser invocada uma única vez".

Segue a implementação do exercício, como você o resolveria usando Call? Ver no JSFiddle.

Bind

O terceiro método de função com a capacidade de mudar o this foi adicionado no ECMAScript5 e difere bastante dos outros dois.
Ao contrário dos outros, ele não executa a função, mas retorna uma outra. O primeiro argumento recebe o valor do this a ser usado na função a ser retornada. Os demais argumentos são os parâmetros que terão valores permanentemente atribuídos dentro da função a ser retornada.

Assim o método Bind acaba cumprindo dois papéis:

  • Mudar o valor do this;
  • Alterar o número de parâmetros de uma função, caso o programador deseje. Essa capacidade de alterar a quantidade de argumentos de uma função é chamada de Currying e será vista com mais detalhes posteriormente.

Dito isso, vamos ao nosso primeiro exemplo, agora usando Bind:

function sayThis(n1,n2){  
    console.log(this * n1 * n2);
}
var thisIs2 = sayThis.bind(2);  
var thisIs2N1Is3 = sayThis.bind(2,3);  
var thisIs2N1Is3N2Is3 = sayThis.bind(2,3,3);  
thisIs2(3,3); //18 - muda this  
thisIs2N1Is3(3); //18 - muda this e atribui n1  
thisIs2N1Is3N2Is3(); //18 - muda this e atribui n1 e n2  

Um bom exemplo de quando o método Bind se torna especialmente útil é quando você precisa manipular valores dentro de callbacks. O exemplo a seguir, também utilizado no post "Como Dominar This", mostra bem isso:


Nota de Conclusão

Call, Apply e Bind são apenas métodos e são tão claros como água cristalina uma vez que se tenha um bom entendimento do this.

Outro ponto que dificulta o entendimento de inciantes desses métodos são exemplos relativamente complexos de utilização, como o desafio do Douglas Crockford. Entretanto, este serve para lhe deixar seguro de que realmente você está dominando a linguagem.

É, por isso, que recomendo para iniciantes que foquem no aprendizado da palavra reservada This e nos exemplos aqui demonstrados com a função sayThis:

function sayThis(n1,n2){  
    console.log(this * n1 * n2);
}

Uma vez entendido os exemplos com essa função o entendimento de ilustrações mais complexas seguirá tranquilamente.

Próximos Passsos

Uma vez que aprendemos a utilizar os métodos Call, Apply e Bind completamos a lacuna que faltava para o domínio da variável this. Agora finalmente estamos prestes a mergulhar no mundo da Orientação a Objeto em JavaScript.

  • O Segredo dos JavaScript Constructors
  • Explorando Objetos em Javascript
  • Aprenda Constructors e Prototypes em Javascript

Sobre o Autor

Johel Carvalho

Johel Carvalho

Engenheiro Civil formado pelo Instituto Militar de Engenharia (IME-RJ) em Dezembro de 2012. Largou a profissão pelo desenvolvimento web, começando com C# e sendo atualmente aficionado por JavaScript.

comments powered by Disqus