Closure em Javascript

E aí povo!

Depois de umas férias de nerdice, queria voltar a falar sobre algumas técnicas muito interessantes que mais uma vez a melhor linguagem existente no planeta implementa. Eu estava devendo uma, quando falei sobre Callbacks em Javascript, os Closures.

Eu gostaria de falar também sobre Currying, que também utiliza closure, mas ia ficar um post muito longo. Recomendo bastante a leitura desse tema no blog do Milfont, onde ele fala sobre Currying em Javascript e sobre como é utilizado em callbacks.

O que é ..

Em ciência da computação e na programação uma closure é uma função que referencia variáveis livres no contexto léxico. Uma closure ocorre normalmente quando uma função é declarada dentro do corpo de outra, e a função interior referencia variáveis locais da função exterior. Em tempo de execução, quando a função exterior é executada, então uma closure é formada, que consiste do código da função interior e referências para quaisquer variáveis no escopo da função exterior que a closure necessita.

Wikipédia: http://pt.wikipedia.org/wiki/Closure

O conceito de Closures foi desenvolvido e primeiramente implementado em Scheme, que é uma linguagem de programação de paradigma funcional.

Embora Javascript não seja essencialmente de paradigma funcional, ela permite usar algumas técnicas de programação funcional, Closure é uma delas.

Como funciona?

Bom, num post passado eu havia dito que os callbacks utilizavam closures, de fato, algumas implementações usam, como?

Olha esse caso:

	function h(f){
		setTimeout(function(){
			f()
		},2000)
	}

Aqui, h recebe um argumento f, portanto f é uma variável livre no escopo de h, e portanto é vista no escopo da função setTimeout. Quando a setTimeout for executar a função f, ela vai saber exatamente quem é a função f, pois está “amarrada” a função h.

function h(f){setTimeout(function(){f()},2000)	}

Vamos tornar mais claro essa noção de variáveis livres. Vou usar mais um argumento agora na função h.

	function h(f, n){
		setTimeout(function(){
			f(n)
		},2000)
	}

E agora eu chamo ela passando uma função como argumento e um número como segundo argumento:

h(function(i){alert(i)}, 20)

Se tudo correr bem, vai dar um alert de 20. Essa função não tem utilidade alguma, serve apenas para ilustrar como ocorre o closure.

Vamos para um exemplo um pouco mais complexo, pois usaremos o retorno de função. Eu considero a programação funcional em js complexa, levando em conta o início do meu aprendizado nessa técnica. Lógico que agora é muito mais simples e claro, mas quando comecei a aprender sobre isso eu pastei. Mas eu me considero meio burrinho, tenho certeza que você vai pegar o jeito da coisa bem mais rápido, se  já não souber…

Vou criar uma função que soma os valores de um array e dentro dessa função vou construir outra função anônima que será retornada.

A idéia é , chamar uma função passando um array como argumento e receber uma outra função que fará a soma dos valores do array por um número, passado como argumento da chamada dessa função retornada.

“Caraaaaaay, que porra é essa?!?!?!?” . Tenha calma, fica mais fácil mostrar do que explicar:

function sumArr(arr){
	return function(by){
		for(var x = 0; x<arr.length; x++)
			arr[x] = arr[x] + by
		return arr
	}
}

Portanto:

var somamais = sumArr([1,2,3])

somamais agora é uma função, que ainda enxerga as variáveis livres de “sumArr”. Então:

 somamais(5) 

>>[6, 7, 8]

Senhoras e senhores, temos o closure ali!!! A função sumArr é tal que possui uma variável de nome “arr” atrelada à uma outra função declarada internamente. Neste nosso caso, uma função anônima retornada após a chamada de “sumArr”.

Não é sensacional !?!??!

Não é maravilhoso !?!?!?!

Não é melhor que sexo ?!?!?!?  ( tá bom…não… ¬¬)

Não é tudo, mas é muito interessante.

Trazendo um pouco para a vida real. Digamos que queremos fazer uma Library, uma biblioteca que use paradigma funcional em javascript para tratar Arrays.

function Library(arg1){
	return function(action){
		return ({				
			'?' : function(arg2){						
					for(var x = 0; x<arg2.length; x++)
						if(arg2[x] == arg1) return true
				return false	
			}
		})[action]
	}
}
Library.begin= function(){return Library}

Bom, o funcionamento desse código eu vou deixar para que você sozinho entenda. Mas, usei closure até não poder mais aí.

Nessa minha Mini-Library, eu só tenho uma funçãozinha de teste, que verifica se um valor existe em um array, retorna um valor booleano, assim:

Library.begin()
	(4)('?')([4, 50, 39, 55, 79])

Responde true, já que o 4 está no array passado como argumento.

Programação funcional tende a ser bastante complicado para se entender, aliás, é esse um dos contras das linguagens de paradigma funcional como Scheme. É muito interessante, em alguns casos bem elegante, mas o código se torna muito confuso a medida que vai aumentando sua complexidade.

Sacaram a melosquência ?

Flw galera, aqueleabraço.