Utilizando Funções em JavaScript

Rubens Yamasaki
Blog TecSinapse

--

Nestes últimos meses começamos a utilizar o React para o desenvolvimento front-end de nossas aplicações. Uma das coisas que foi fundamental para possibilitar o entendimento desta biblioteca foi aprender a programar em JavaScript. Deste modo, vou falar um pouco sobre um recurso muito utilizado no JavaScript que é a função.

1. O que é uma função no JavaScript?

Podemos dizer que uma função consiste em um objeto que possui código executável. É um recurso que fornece o encapsulamento no JavaScript, pois o que é definido dentro de uma função não pode ser acessado externamente. Considere o exemplo a seguir:

Exemplo-1.1
function teste() {
const var1 = 'Valor';
function teste2() {
console.log('Função Interna');
}
teste2();
}
teste();
console.log(var1); //Ocorre erro ao executar esta linha.

Ao executarmos o código apresentado no Exemplo-1.1 teremos como saída no console a frase “Função Interna”, porque invocamos a função teste que realiza a chamada da função interna teste2 que imprime a frase “Função Interna”. Porém ao executar a linha console.log(var1) vamos obter um erro pelo fato de var1 ser declarado dentro da função teste, que acaba não sendo acessível no escopo externo à função. Esta mesma regra vale se ao invés de executarmos console.log(var1) executássemos a chamada da função teste2, pois ela também não está acessível no escopo externo da função teste.

2. Conceito de funções de primeira classe

Um ponto interessante sobre as funções em JavaScript é o fato de serem funções de primeira classe, ou seja, podem ser passadas como parâmetros de uma função, atribuídas a uma variável ou retornadas por meio de outra função.

A seguir podemos ver um exemplo de uma função sendo atribuída a uma variável.

Exemplo-2.1
var teste = function() {
console.log('Test');
}
teste(); //realizando chamada de função atribuída à variável teste

No Exemplo-2.1 podemos observar que a função é atribuída à variável teste, e em seguida realizamos a chamada da função por meio do comando teste(), de modo que vamos obter na saída do console a palavra “Test”.

A seguir temos um exemplo de funções que são passadas como parâmetro para outras funções:

Exemplo-2.2function executaOperacao(numero1, numero2, operacao) {
return operacao(numero1, numero2);
}
function soma(numero1, numero2) {
return numero1 + numero2;
}
function multiplicacao(numero1, numero2) {
return numero1 * numero2;
}
console.log(executaOperacao(1, 1, soma));
console.log(executaOperacao(2, 2, multiplicacao));

No Exemplo-2.2 definimos duas funções com os nomes de soma e multiplicacao, ambas recebem como parâmetro 2 valores que serão somados ou multiplicados respectivamente.

Em paralelo existe a função executaOperacao que recebe 3 parâmetros nos quais numero1 e numero2 são valores numéricos e o parâmetro operacao é uma função. A função executaOperacao realiza a chamada da função operação que pode ser soma ou multiplicacao.

Executando a chamada de executaOperacao(1, 1, soma) vamos obter o valor igual a 2 ,executando a chamada executaOperacao(2, 2, multiplicacao) vamos obter o valor 4.

O conceito de funções de primeira classe na linguagem JavaScript também pode ser chamado de lambda.

Se você já programou na linguagem Java provavelmente deve ter ouvido falar deste recurso que foi disponibilizado a partir da versão 8. Caso deseje saber mais detalhes sobre o uso do lambda no Java, existe uma postagem que escrevi sobre este assunto e que pode ser acessada no link abaixo:

A seguir temos um exemplo de funções que estão sendo retornadas por meio de outras funções:

Exemplo-2.3
function imprimirTexto() {
return function() {
console.log("Imprimindo texto!");
}
}
imprimirTexto()();
var funcaoInterna = imprimirTexto();
funcaoInterna();

No Exemplo-2.3 é apresentada a função imprimirTexto que retorna uma função anônima. Existem 2 formas de executar a função retornada. Uma das formas é executando o comando imprimirTexto()(), outra forma é atribuir o retorno da função imprimirTexto a uma variável e em seguida utiliza-la para realizar a chamada da função. Podemos observar que isto é feito no Exemplo-2.3 por meio da variável funcaoInterna.

3. Sintaxes para criação de funções

Apresento aqui 3 formas diferentes para criação de funções em JavaScript.

Function declaration:

Basicamente nesta sintaxe nós definimos o nome da função, os parâmetros e o seu retorno, lembrando que nem o parâmetro ou o retorno de valor são obrigatórios.

A seguir podemos ver um trecho de código que faz uso de funções que obedecem a sintaxe da function declaration:

Exemplo-3.1
imprimeSoma(4, 5);
function imprimeSoma(a, b) {
console.log(soma(a, b));
}
function soma(a, b) {
return a + b;
}

Se executarmos o código do Exemplo-3.1 vamos obter o valor 9 impresso no console. Se repararmos, a chamada da função imprimeSoma é feita antes de sua criação e mesmo assim o código será executado sem erros.

Function expression:

A function expression basicamente consiste em atribuir uma função a uma variável. As funções que são atribuídas a uma variável podem ou não possuir nomes. Podemos ver alguns exemplos de funções que seguem a sintaxe da function expression a seguir:

Exemplo-3.2//Function expression sem nome
var soma = function (a, b) {
return a + b;
}
//Function expression com o nome imprimir
var imprimeSoma = function imprimir(a, b) {
console.log(soma(a, b));
}
imprimeSoma(4, 5);

Arrow Functions

A sua sintaxe é muito parecida com a function expression, porém um pouco mais simples. A seguir podemos ver um exemplo de algumas funções do tipo arrow function:

Exemplo-3.3var soma = (a, b) => {
return a + b;
}
var imprimeSoma = (a, b) => {
console.log(soma(a, b));
}
imprimeSoma(4, 5);

4. Função Construtora e Função Fábrica

No JavaScript nós temos o objeto que consiste em um conjunto de chaves e valores que pode ser criado por meio de uma função construtora ou uma função fábrica.

Função Construtora

A função construtora faz uso do operador new em sua sintaxe. No exemplo a seguir podemos ver a construção de um objeto utilizando uma função construtora:

Exemplo-4.1var Produto = function (nome, quantidade) {
this.nome = nome,
this.quantidade = quantidade
}
var produto = new Produto("Martelo", 30);
console.log(produto);

No Exemplo-4.1 definimos uma variável que recebe uma função anônima. Esta função retorna um objeto que possui os campos nome e quantidade. Logo em seguida criamos uma variável de nome produto que recebe o objeto. A chamada da função ocorre por meio do operador new.

Quando utilizamos a função construtora, devemos definir o nome da variável que recebe a função com letra maiúscula, esta convenção é utilizada para saber que devemos utilizar o operador new durante a sua invocação.

O operador new faz a criação do objeto definido na função construtora e em seguida atribui os parâmetros nome e quantidade em suas respectivas variáveis por meio da palavra reservada this. Na função Produto a palavra this faz referência ao objeto que está sendo criado.

Função Fábrica

A função fábrica possui um conceito mais simples, basicamente consiste em uma função que retorna um objeto com valores que são definidos em seus parâmetros. A seguir podemos observar um exemplo de função fábrica.

Exemplo-4.2function criarProduto(nome, quantidade) {
return {nome: nome, quantidade: quantidade}
}
var produto = criarProduto("Martelo", 30);
console.log(produto);

5. Funções dentro de objetos

JavaScript não possui o conceito de método definido em sua linguagem. Porém conseguimos simular este comportamento criando objetos que possuem funções.

A seguir podemos ver um exemplo do uso de funções definidas dentro de objetos:

Exemplo-5.1var retangulo = {
altura: 5,
largura: 4,
getArea: function() {
return this.altura * this.largura;
}
}
console.log(retangulo.getArea()); //saída será 20

No Exemplo-5.1 criamos um objeto que vamos considerar ser um quadrilátero e será atribuído a uma variável de nome retângulo, deste modo ele vai possuir os atributos altura e largura e por último a função getArea, que é responsável por calcular a área do quadrilátero por meio dos atributos altura e largura.

É interessante observarmos que a função getArea utiliza a palavra reservada this. O this pode assumir diferentes comportamentos dependendo da forma como a função na qual ela pertence é chamada. Quando executamos retangulo.getArea() o this faz referência ao objeto retangulo, de modo que ele consegue acessar os atributos altura e largura.

Porém a palavra reservada this pode ter outro comportamento se considerarmos o seguinte exemplo:

Exemplo-5.2
var retangulo = {
altura: 5,
largura: 4,
getArea: function() {
return this.altura * this.largura;
}
}
var retangulo2 = {
altura: 2,
largura: 2
}
console.log(retangulo.getArea.call(retangulo2)); //saída será 4

No Exemplo-5.2 vamos obter como saída o valor 4. Neste caso recuperamos a função getArea declarada no objeto retangulo e realizamos a chamada do método call passando como parâmetro retangulo2, que será o objeto no qual a palavra reservada this utilizada na função getArea vai apontar.

6. Closures

Um closure consiste de uma função que é capaz de acessar qualquer variável presente em seu escopo durante o momento de sua criação. Para ficar mais claro vamos considerar o seguinte exemplo:

Exemplo-6.1

function exemploClosure() {
var nome = "Closure";
function imprimirNome() {
console.log(nome);
}
return imprimirNome;
}
var funcaoImprimir = exemploClosure();
funcaoImprimir(); //será impresso a palavra Closure

No Exemplo-6.1 nós declaramos a função exemploClosure que possui a função imprimirNome que por sua vez imprime a variável nome. Isto foi possível porque nome e imprimirNome estão no mesmo escopo, pois foram declaradas dentro da função exemploClosure.

Aproveitando o conceito de closure podemos refatorar o Exemplo-5.1 da seguinte forma

Exemplo-6.2//Exemplo antes de refatorar
var retangulo = {
altura: 5,
largura: 4,
getArea: function() {
return this.altura * this.largura;
}
}
console.log(retangulo.getArea()); //saída será 20
//Exemplo-5.1 refatorado
function criarQuadrilatero(altura, largura) {
return {altura: altura,
largura: largura,
getArea: function() {
return altura * largura;
}
}
var quadrilatero1 = criarQuadrilatero(4, 7);
console.log(quadrilatero1.getArea());
var quadrilatero2 = criarQuadrilatero(2, 2);
console.log(quadrilatero2.getArea());

O primeiro ponto refatorado foi criar a função fábrica com o nome criarQuadrilatero, que retorna o mesmo objeto definido no Exemplo-5.1. Outro ponto alterado é o fato de não utilizarmos mais a palavra reservada this dentro da função getArea.

Logo após definir a função fábrica podemos observar a criação das variáveis quadrilatero1 e quadrilatero2 e a chamada da função getArea.

7.Encapsulamento

Um ponto muito interessante das funções no JavaScript é o fato de podermos encapsular as informações por meio das funções.

Exemplo-7.1
var retangulo = {
altura: 5,
largura: 4,
getArea: function() {
return this.altura * this.largura;
},
isQuadrado: function() {
return this.altura === this.largura;
}
}
console.log(retangulo.altura);

No Exemplo-7.1 observamos que após definirmos a variável retangulo nós conseguimos acessar a variável altura diretamente por meio do comando retangulo.altura. Podemos refatorar este código para tornar os atributos altura e largura encapsulados da seguinte forma:

Exemplo7.2
var criarQuadrilatero = function(altura, largura) {
var altura = altura;
var largura = largura;
return {
getAltura : function() {
return altura;
},
getLargura : function() {
return largura;
},
getArea : function() {
return altura * largura;
},
isQuadrado : function() {
return this.altura === this.largura;
}
}
}
var retangulo = criarQuadrilatero(5, 7);
console.log(retangulo.getArea()); //será impresso 35
console.log(retangulo.getAltura()); //será impresso 5
console.log(retangulo.altura); //será impresso undefined

No Exemplo-7.2 encapsulamos altura e largura dentro da função criarQuadrilatero, que por sua vez retorna um objeto que contém um conjunto de funções que conseguem acessar estas variáveis.

Podemos observar que ao tentar acessar a variável diretamente por meio do comando retangulo.altura vamos obter o valor undefined, porém as funções getAltura e getLargura conseguem acessar as variáveis altura e largura.

6.Referências

Este artigo aborda apenas alguns conceitos das funções em JavaScript. Existem muitos outros recursos que o JavaScript fornece, deste modo vou deixar como referência alguns materiais que utilizei para estudar:

  • Desvendando a linguagem JavaScript:

Esta é uma playlist que contém algumas videoaulas ministradas pelo Rodrigo Branas sobre a linguagem JavaScript. Nesta playlist são abordados diversos assuntos como tipos de variáveis, conceito de funções e formas de se trabalhar com listas e objetos.

As aulas são bem didáticas e me ajudaram muito no aprendizado da linguagem.

  • Arrow Functions e Closures

Nestes links são apresentados os conceitos de Arrow Functions e Closures. O material pertence ao site developers.mozilla.org.

Antes de finalizar aqui eu gostaria de agradecer ao Ruither Borba por ter feito a revisão desta postagem, sugerindo melhorias e correções de algumas afirmações que fiz.Vou deixar um link para que vocês também possam acessar e seguir o perfil dele no Medium:

Espero que esta postagem tenha ajudado a compreender o uso das funções no JavaScript. Muito obrigado e até a próxima. :)

--

--