Entendiendo scopes and closure en javascript de manera sencilla
Scope y closures fueron un dolor de cabeza en mis inicios y no dudo que muchos esten batallando hoy en día yendo de blog en blog tratando de entender. Hay un gran numero de blog alla afuera y a pesar de que algunos son sencillos otros asumen que ya se saben un par de lenguajes que se tienen algo de experiencia en programación. En esta entrada intentare de explicar de la manera mas sencilla que son los scopes y los closures y mas que nada en que nos pueden ayudar, con que se comen ya que eso es lo que realmente importa.
Scope
Scope se refiere mas que nada al alcance que tenemos de las variables y el contexto donde son ejecutadas, es decir en que lugar de tu script estas accediendo a esa variable o content execution(contexto de ejecución). Escencialmente existen dos tipos de variables, las variables locales y las globales. Las variables tienen un scope o function-scope dentro de la función y las funciones dentro de funciones tienen el mismo scope o alcance.
GLOBAS SCOPE
Cuando hablamos de algo global nos referimos a que podemos acceder a ello desde cualquier lugar. Hay que entender que cuando declaramos alguna variable, internamente desde el lenguaje es como si corriéramos una función o creáramos un objeto.
var nombre = "juan"; //Esta variable ha sido declarada global
function saludar(){
return console.log("hola juan");
}
En el ejemplo anterior la variable como la función estan fuera de las funciones pero están dentro de window, window es un objeto que viene en todos los navegadores y todos los objetos, variables y funciones automáticamente pasan a ser miembros del objeto window por debajo de su jerarquía cuando son declarados fuera de las fuciones.
Tomemos el ejemplo:
const saludo = "hola"; // declarada como constante, su valor no cambiará
Una vez declarada una variable con un scope global puede ser usada en todo el script o código. A pesar de que las puedes declarar globales se aconseja que no, ya que pueden chocar con otras variables que intentes declarar de nuevo.
Si declaras tus variables con const y let tus variables no las podras decrarar otra vez. Esto no sucede si las declaras con var ya que lo que pongas al ultimo sobreescribe lo anterior.
var saludo = "buenas tardes";
var saludo = "buenas noches";
console.log(saludo); // nos dará "buenas noches"
VARIABLES LOCALES
Cuando las variables son locales quiere decir que solo tienes acceso desde cierta parte del script. Hay dos tipos de variables locales, es decir que tienen un scope local, las que están adentro de una funcion y las que están adentro de los brackets o blockes.
Veamos un ejemplo de una variable local:
funcion dimeChistes(){
var chiste = "Este era pepito y pepita...";
return alert(chiste); // Aqui el scope es local, dentro de la funcion
}
dimeChiste() //Te dirá el chiste
alert(chiste); //Te dará un error, como undefined, es decir no definido
Chiste solo esta disponible dentro de la funcion dimeChistes(). Afuera no hay nada, chiste no existe!! Sin embargo si la declaras sin var automáticamente se convierte en global, lo que la haría accesible afuera. Lo mismo sucederá con una función dentro de una función.
Hasta ahorita todo bien y chido, ahora vayámonos rápido con los closures
Para tratar de dar una explicación breve y entendible, un closure es una función dentro de otra función que no se ejecuta, siendo que la primera la regresa como valor a la segunda y la pone lista para usarse o ejecutarse en cualquier momento por el script cargando con el contexto y variables de la función padre.
Hay que entender el Content execution, Local Execution Context, Execution Stack y Hoisting. Wow!! Cuatro terminos bien raros, pero no hay que asustarse, el primero se refiere al contexto global de ejecución, mientras que el segundo se refiere al local, es decir a la ejecución de funciones y variables dentro de una función. El execution stack es como una lista de las funciones que tenemos corriendo o de los contextos de ejecución, mismo que dentro de ellos podremos tener otros contextos corriendo. Es decir contextos locales. Por último hoisting se refiere a poner el código en la memoria listo y accesible para usarse, llamando o corriendo una función por ejemplo aun antes de ser declarada. Aunque en realidad lo que pasa es que corre el script, visualiza las funciones declaradas y las pone en la memoria, después corre las funciones que hayan sido llamadas.
Tomemos como ejemplo para hoisting
console.log(grita)
function grita(){
console.log("hooolaaaa!!");
}
En la funcion anterior se obtiene el resultado a pesar de estarse ejecutando ante de la función.
Ahora veamos un ejemplo de closure y context execution o local context execution.
function multiplicar(x){
var solucion = "La solucion es: ";
return function(y){ return solucion+(x * y);}
}
var multiplicarPorTres = multiplicar(3);
console.log(multiplicarPorTres(5)); // Nos regresa "La solucion es: 15"
Por qué?
La razón es sencilla, cuando declaramos la función multiplicar adentro existía otra función, pero no se ejecuto, la función se ejecuta justo cuando declaramos multiplicarPorTres, de lado derecho llamamos multiplicar(3), notese los paréntesis, que dan la orden de ejecutar la función. Sin embargo la función interna no corrió, solo digamos que se declaro e inicializo la variable "x" y la variable "solucion" y se regreso la función interna como valor lista para ser ejecutada. En el contexto de ejecución ahora existe la variable x con valor 3. Ahora cuando se consolea, se corre la nueva variable que contiene una función interna, de hecho la variable multiplicarPorTres es la función interna de multiplicar, pero consigo carga con la variable "x" de valor 3 y con "solucion" con valor de string. A multiplicar por tres le mandamos otro numero que ahora pasa a ser "y" se declara, busca x localmente, pero como no la encuentra busca en su entorno de ejecución y voila!! Ahi esta "x" con valor de 3.
Y de esa manera terminamos esta entrada, esperemos que les sirva esta explicación.
Un momento mientras cargamos los comentarios
{{item.date}}
{{item.image}}
{{subitem.date}}
{{subitem.image}}