6.1 Conceito de Closures
Closures são uma das mais poderosas e importantes conceitos em JavaScript. Elas permitem que funções lembrem seu ambiente léxico mesmo depois de terem sido executadas. Nesta aula, vamos explorar o conceito de closures, suas características e fornecer vários exemplos de uso.
Closure em JavaScript é uma combinação de uma função e do ambiente léxico no qual a função foi declarada. Closure permite que uma função "lembre" e acesse variáveis e outras funções do seu escopo externo mesmo depois que a função externa foi executada.
Principais propriedades das closures:
- Ambiente léxico: contexto no qual a função foi declarada, incluindo todas as variáveis disponíveis no momento da declaração.
- Preservação do contexto: uma função com closure pode preservar o acesso a variáveis do escopo externo mesmo após a execução dessa função externa.
6.2 Exemplos de funcionamento das closures
Exemplo 1: Closure simples
Neste exemplo, innerFunction() tem acesso à variável outerVariable do seu escopo externo mesmo após a execução de outerFunction().
function outerFunction() {
let outerVariable = 'I am from the outer function';
function innerFunction() {
console.log(outerVariable);
}
return innerFunction;
}
const closure = outerFunction();
closure(); // Vai exibir: I am from the outer function
Exemplo 2: Contador usando closure
Neste exemplo, a função contador preserva o valor da variável count e a incrementa a cada chamada.
function createCounter() {
let count = 0;
return function() {
count++;
return count;
};
}
const counter = createCounter();
console.log(counter()); // Vai exibir: 1
console.log(counter()); // Vai exibir: 2
console.log(counter()); // Vai exibir: 3
Exemplo 3: Closure em loop
Closures são frequentemente usadas para preservar valores de variáveis em loops.
Neste exemplo, cada função dentro do array arr "lembra" o valor da variável i no momento da sua criação graças ao escopo de bloco de let:
function createArrayWithClosures() {
let arr = [];
for (let i = 0; i < 3; i++) {
arr[i] = function() {
console.log(i);
};
}
return arr;
}
const closures = createArrayWithClosures();
closures[0](); // Vai exibir: 0
closures[1](); // Vai exibir: 1
closures[2](); // Vai exibir: 2
6.3 Cenários complexos de uso de closures
Exemplo 1: Aplicação parcial de função (partial application)
Closures permitem criar funções parcialmente aplicadas, mantendo alguns argumentos fixos.
Neste exemplo, a função multiply() retorna uma função que multiplica o argumento passado b pelo argumento fixo a.
function multiply(a) {
return function(b) {
return a * b;
};
}
const double = multiply(2);
console.log(double(5)); // Vai exibir: 10
console.log(double(10)); // Vai exibir: 20
Exemplo 2: Esconder dados (data hiding)
Closures podem ser usadas para criar variáveis e métodos privados.
Neste exemplo, as variáveis _name e _age são privadas e acessíveis apenas através dos métodos do objeto:
function createPerson(name, age) {
let _name = name;
let _age = age;
return {
getName: function() {
return _name;
},
getAge: function() {
return _age;
},
setName: function(newName) {
_name = newName;
},
setAge: function(newAge) {
_age = newAge;
}
};
}
const person = createPerson('John', 30);
console.log(person.getName()); // Vai exibir: John
person.setName('Jane');
console.log(person.getName()); // Vai exibir: Jane
console.log(person.getAge()); // Vai exibir: 30
Exemplo 3: Memoização
Memoização é uma técnica de otimização onde os resultados de uma função são armazenados para evitar cálculos repetidos para os mesmos dados de entrada.
Neste exemplo, a função memoize() utiliza closure para armazenar o cache de resultados calculados da função fn():
function memoize(fn) {
const cache = {};
return function(...args) {
const key = JSON.stringify(args);
if (cache[key]) {
return cache[key];
}
const result = fn(...args);
cache[key] = result;
return result;
};
}
function slowFunction(num) {
console.log('Computing...');
return num * 2;
}
const memoizedFunction = memoize(slowFunction);
console.log(memoizedFunction(5)); // Vai exibir: Computing... 10
console.log(memoizedFunction(5)); // Vai exibir: 10 (resultado do cache)
GO TO FULL VERSION