Execution context o el contexto de ejecución de javascript - El Mundo de Angular

Execution context o el contexto de ejecución de javascript

¿No estaría bueno que cuando le pedimos a un albañil que nos construya una casa, ésta venga con puertas y ventanas colocadas? ¿y con el piso? ¿y el techo? ¿y qué tal el baño instalado… y la cocina? O sea, el Sr. albañil nos prepara todo un «contexto» para poder usar nuestra nueva casa. Bueno, de forma análoga, cada vez que le pedimos a Javascript que nos cree una función, no sólo nos crea esa función sino TODO un Contexto para Ejecutarla (o Execution Context)

Execution Context

El Contexto de ejecución pensálo como un Wrapper (o algo que envuelve) con «cositas» que se crean cada vez que vos creas una función. Estas «cositas» te ayudan a manejar el código que se está ejecutando en un momento dado, y se crean para facilitarte la vida y vos no tengas que crear absolutamente nada. Entre esas cosas están objetos globales, la palabra reservada this, variables externas y otras más.

Un nuevo Execution Context es creado cada vez que se ejecuta una función. Y también, hay un Execution Context global que es el que se crea cuando ejecutás tu código al inicio (sin que esté dentro de ninguna función)

 

Pero volvamos un paso mas atrás, veamos esa «Pila de ejecución». Cuando nuestro código inicia se crea un Contexto de Ejecución Global, es como ejecutar una función pero a nivel global, nosotros no creamos esa función todo ésto lo hace el motor de Javascript. Volviendo a nuestro ejemplo, cuando el motor de Javascript llega a la línea 1 crea nuestro Contexto de Ejecución y lo apila en una pila de ejecución creando un nuevo Contexto de Ejecución: «Execution Context Global«.

 

Cuando nuestro código llega a la línea 11 y ejecuta la funcion «b»


b();

se crea un nuevo Contexto de Ejecución: El Contexto de Ejecución de la función «b». Nuestro actual Contexto «Execution Context Global» queda en segundo plano y el motor de Javascript pasa a crear y ejecutar el contexto de la función «b».

Recordemos que una pila funciona de la siguiente forma: El ultimo que entra es el primero que sale, y traducido a nuestros Contextos de Ejecución, el ultimo Contexto de Ejecución que entra en la pila, sera el primero en ser ejecutado. Es por eso que el motor de Javascript cambia del contexto de ejecución Global al Contexto de Ejecución de la función «b».

Ahora pasa lo mismo con la función «a» cuando llega a la línea que ejecuta la función a():


function b() {
console.log('b');
a();
}

 

En nuestra pila de ejecución se crea un nuevo contexto (Execution Context de la función a) y el motor pasa a ejecutar ese contexto, dejando «en espera» al contexto anterior:

Una vez que finaliza de ejecutarse la función «a» su contexto desaparece y el motor de Javascript pasa a ejecutar el contexto «anterior», en este caso sería el Contexto de Ejecución de la función «b»:

Y lo mismo al finalizar de ejecutarse la función «B», o mejor dicho su contexto, se lo saca de la pila y se ejecuta el contexto anterior; en el ejemplo, al no haber más Execution Context de ninguna función, el Contexto de Ejecución que se ejecuta es el Global:

Y para terminar, cuando este contexto finaliza, o sea cuando nuestro programa finaliza, se vacía la pila

Fácil ¿no?

Las Fases de un Execution Context

En todos los Execution Context, aunque lo haya graficado como una única unidad de tiempo, existen dos fases bien diferenciadas: La Fase de Creación y la Fase de Ejecución. Es MUY importante saber de estas fases ya que, entender estas faces es entender por qué pasan algunas cosas «raras» en Javascript.

Fase de Creación

En la Fase de Creación del Execution Context, como mencionamos anteriormente, se crean varias cosas:

  • Objeto global: cuando ejecutás tu código Javascript en tu browser, este objeto es «window» y es un objeto que hace referencia a tu browser.
  • this: es una palabra reservada que hace referencia al «lugar» donde estás parado. El valor de «this» va cambiando dependiendo del Execution Context en que te encuentres. Como dato, en el Execution Context Global (cuando inicia tu programa), «this» es igual al objeto global.
  • Tus variables y funciones: en esta etapa también se reserva espacio en memoria para TODAS las variables y funciones de tu código.

En este último punto cabe una aclaración: Javascript no se comporta como el resto de los lenguajes (por si no te diste cuenta antes, te lo aclaro :P ). En Javascript podemos hacer lo siguiente:


console.log(a);
var a = 'Hola mundo';

¿Ves el «problema»? En muchos otros lenguajes, como por ejemplo Java, si hiciéramos ésto, ¡nuestro código explotaría! Pero en Javascript no. En Javascript, cuando se crea el Contexto de Ejeución (Fase de Creación) lo que hace el motor de Javascript es recorrer todo el código buscando instanciar todas las variables y funciones que creemos. Cuando encuentra algo como:


var a = 'Hola mundo';

lo que hace es reservar memoria para esa variable «a» y asignarle el valor «undefined».

Y lo mismo si quisiéramos definir una función de esta forma:



var f = function() {

}


Sí, sí ¡esto se puede hacer! Pasaría lo mismo, en la Fase de Creación de nuestro Execution Context se crearía la variable f, se reservaría espacio en memoria y se le asignaría «undefined».

¡Y eso es todo! no se «ejecuta» NADA, no se ejecuta ninguna función en este punto, sólo se «crean» cosas.

¿Y entonces qué imprime este código?


console.log(a);
var a = 'Hola mundo';

¡Correcto! Imprimiría la palabra reservada «undefined»  ya que la variable «a» no fue «asignada» en el momento que se llama «a»:


console.log(a);

Sólo fue guardado espacio en memoria, y se le asignó el valor por defecto «undefined».

 

Fase de Ejecución

Es en ésta fase donde se asignan valores en Javascript, es en ésta etapa en donde el ejemplo:


console.log(a);
var a = 'Hola mundo';

var a= ‘Hola mundo’ se ejecuta y a la variable «a» se le asigna el valor ‘Hola mundo’

Si quisiéramos imprimir el valor ‘Hola mundo’ en consola, lo que deberíamos hacer es invertir el orden en el código:


var a = 'Hola mundo';
console.log(a);

 

De esta forma, definiríamos la variable «a» en la Fase de Creación del Execution Context y asignaríamos el valor a la variable en la fase de ejecución del Execution Context.

Nota importante

Este código:


console.log(a);
var a = 'Hola mundo';

El cual nos imprime ‘undefined’ en consola, no es lo mismo  que no definir NUNCA una variable:


console.log(a);

Este código nos arrojaría un ERROR: Uncaught ReferenceError: a is not defined

Tiene lógica porque la variable «a» nunca fue definida en ningún lado, y ésto, por más que Javascript sea «raro», no es algo que se pueda hacer.

 

Conclusiones

Sabiendo qué es el Contexto de Ejecución, podemos saber qué cosas se crean cuando creamos y ejecutamos una función. Además, podemos seguir el orden de cómo se ejecutan las funciones, y ésto nos abre un montón de conceptos que veremos en otros posts. Por otro lado, al saber las dos etapas de los Execution Context (creación y ejecución) podemos entender cómo es que algunas variables valen ‘undefined’ y otras tienen el valor que le asignamos. Lo último depende del orden en que declaremos nuestras variables y funciones. ¿Verdad que ahora Javascript se ve un poquito menos raro?

About the Author

Mi nombre es Gustavo Hernán Dohara, soy Ingeniero en Sistemas y, sobre todas las cosas, soy un apasionado por la tecnología; tengo más de 10 años de experiencia en diferentes tecnologías y he decidido compartir mis conocimientos y experiencias con cualquiera que desee aprender: alumnos, empleados, freelancers y vos. Al ritmo que cada uno pueda, en el horario en que cada uno pueda y en el lugar que cada uno elija.