Contexto de Ejecución

Hay 3 Tipos de Código Ejecutable en ECMAScript:

  • Código Global: El código que está a nivel de Programa. No incluye el código que está dentro de las funciones
  • Código de Función: El código dentro de una función
  • Código de Eval: El código dentro de una expresión eval

Cuando alguno de estos tipos de código se ejecuta, lo hace dentro de un Contexto de Ejecución

Los contextos de ejecución forman una pila.
Es decir, primero se ejecutará código global en su propio contexto de ejecución, este código puede llamar a una función que se ejecutará en su propio contexto de ejecución, y así sucesivamente
Con cada nueva invocación a una función se entra en un nuevo contexto de ejecución

More info


Objeto Variable (Variable Object)

AbstractVO (generic behavior of the variable instantiation process)
║
╠══> GlobalContextVO
║ (VO === this === global)
║
╚══> FunctionContextVO
(VO === AO, <arguments> object and <formal parameters> are added)

Cada contexto de ejecución tiene lo que se llama un Objeto Variable.

Las variables ( var, VariableDeclaration), funciones (FunctionDeclaration, FD) y parámetros formales de la función declaradas en el contexto son añadidas como propiedades de este Objeto Variable

En un código global

Cuando se entra en el contexto de ejecución de un Código Global, se utiliza un Objeto Global como Objeto Variable.

VO(globalContext) === global;

El Objeto Global es el objeto que se crea antes de entrar en ningún contexto de ejecución. Sus propiedades son accesibles desde cualquier parte del código, y existe durante la ejecución del programa.

/* remember that `this` refers to global object when in global scope */
var GLOBAL_OBJECT = this;
var foo = 1;
GLOBAL_OBJECT.foo; // 1
foo === GLOBAL_OBJECT.foo; // true
function bar(){}
typeof GLOBAL_OBJECT.bar; // "function"
GLOBAL_OBJECT.bar === bar; // true
>>> var a = 'test'
>>> a === 'test' // directly, is found in VO(globalContext): "test"
true
>>> window === this
true
>>> window['a'] === 'test' // indirectly via global===VO(globalContext):
true
>>> a === this.a
true
>>> var aKey = 'a';
>>> window[aKey] === 'test' // indirectly, with dynamic property name: "test"
true

En un código de función

Cuando se entra en el contexto de ejecución de un Código de Función, se utiliza un Objeto de Activación (AO) como Objeto Variable.

VO(functionContext) === AO;

Un Objeto de Activación es creado al entrar en el contexto de una función e inicializado con la propiedad arguments (objeto arguments con las propiedades callee y length)

More info:

function foo(x, y, z) {

  // quantity of defined function arguments (x, y, z)
  console.log(foo.length == 3); // true

  // quantity of really passed arguments (only x, y)
  console.log(arguments.length === 2); // true

  // reference of a function to itself
  console.log(arguments.callee === foo); // true

  // parameters sharing
  console.log(x === arguments[0]); // true
  console.log(x === 10); // true

  arguments[0] = 20;
  console.log(x === 20); // true

  var x = 30;
  console.log(arguments[0] === 30); // true

  // however, if we don’t pass and argument z
  // related index-property of the arguments
  // is not ‘linked’ with z 

  var z = 40;
  console.log(arguments[2] === undefined); // true
  console.log(z === 40); // true

  arguments[2] = 50;
  console.log(arguments[2] === 50); // true

  console.log(arguments); 
  console.log(arguments[2]);

}

foo(10, 20);

More info:


Fases de Procesamiento del Código

El procesamiento del código (al llamar a una función) se divide principalmente en 2 fases:

  1. La entrada en el Contexto de Ejecución (preparamos el terreno)
  2. La ejecución del Código

1. Al entrar en el Contexto de Ejecución

Al entrar en el Contexto de Ejecución (pero antes de la ejecución del código), el Objeto Variable se rellena con las siguientes propiedades (y en este orden):

1.- Para cada Parámetro Formal de la función (si estamos en el contexto de ejecución de una función)

  • Se crea una propiedad en el Objeto Variable con el mismo nombre y valor que el parámetro formal
  • Si no se le pasa el parámetro a la función, se crea una propiedad en el Objeto Variable con el mismo nombre y con valor undefined

2.- Para cada Declaración de Función (FunctionDeclaration, FD)

  • Se crea una propiedad en el Objeto Variable con el mismo nombre y con su correspondiente objeto-función como valor
  • Si el Objeto Variable ya contiene una propiedad con el mismo nombre, se reemplaza su valor y atributos

3.- Para cada Declaración de Variable (var, VariableDeclaration)

  • Se crea una propiedad en el Objeto Variable con el nombre de la variable y con el valor undefined
  • Si el Objeto Variable ya contiene una propiedad con el mismo nombre, esta declaración de variable NO reemplaza su valor

Ejemplo:

function test(a, b) {
  var c = 10;
  function d() {}
  var e = function _e() {};
 (function x() {});
}
test(10); // call

… al entrar en el contexto de la function test con el parámetro pasado 10, el Objeto de Activación queda asi:

AO(test) = {
  a: 10,
  b: undefined,
  c: undefined,
  d: <reference to FunctionDeclaration "d">
  e: undefined
};

2. Al empezar la Ejecución del Código

Al empezar la Ejecución del Código el Objeto de Activación (Objeto Variable) ya está relleno con sus propiedades (aunque no todas ellas tienen los valores reales pasados, la mayoría tienen el valor inicial undefined ):

… en el ejemplo anterior el Objeto de Activación (AO/VO) se modificaría asi durante la interpretación del código

AO['c'] = 10;
AO['e'] = <reference to FunctionExpression "_e">;

Otro Ejemplo:

(function () {

  console.log (typeof(x) === 'function'); // true 

  var x = 10; 
  console.log (x === 10); // true 

  x = 20; 
  function x() {} 

  console.log (x === 20); // true

}())

… al entrar en el Contexto de Ejecución

VO = {};
VO['x'] = <reference to FunctionDeclaration "x">
// found var x = 10;
// if function "x" would not be already defined
// then "x" be undefined, but in our case
// variable declaration does not disturb
// the value of the function with the same name
VO['x'] = <the value is not disturbed, still function>

… y al ejecutar el código

VO['x'] = 10;
VO['x'] = 20;


Tipos de Funciones

Una Function Declaration (FD) es una función que:

  • Tiene un nombre obligatorio
  • En el código puede aparecer a nivel raíz o en el cuerpo de otra función
  • Se guardan en el Objeto Variable del Contexto de Ejecución (es decir, en tiempo de ejecución ya están disponibles)
foo();

function foo() {
  alert('foo');
}

Una Function Expression (FE) es una función que:

  • Puede tener un nombre opcional
  • En el código sólo puede aparecer en la posición de una expresión
  • Su definición no afecta al Objeto Variable del Contexto de Ejecución
  • Se crea en tiempo de ejecución
var foo = function () {
  alert('foo');
};

foo();
// in parentheses (grouping operator) can be only an expression
(function foo() {});
// in the array initialiser – also only expressions
[function bar() {}];
// comma also operates with expressions
1, function baz() {};

… pese a que una FE puede tener nombre, las distinguimos de una FD en que las FE sólo puede estar en la posición de una expresión

// FE is not available neither before the definition
// (because it is created at code execution phase),
alert(foo); // "foo" is not defined
(function foo() {});
// nor after, because it is not in the VO
alert(foo); // "foo" is not defined

… las FE son creadas en tiempo de ejecución

var foo = {};

(function initialize() {
  var x = 10;
  foo.bar = function () {
    alert(x);
  };
})();

foo.bar(); // 10;
alert(x); // "x" is not defined

Si queremos llamar a una función directamente desde su definición y la función no está en una expression position, tendremos que encerrarla entre paréntesis

Con esto, lo que hacemos en transformar manualmente la función en una Function Expression (FE)

(function foo(x) {
  alert(x);
})(1); // OK, it's a call, not a grouping operator, 1
1, function () {
  alert('anonymous function is called');
}();

// or this one
!function () {
  alert('ECMAScript');
}();

// and any other manual
// transformation

… en el caso en que la función ya esté en una expression position, no hacen falta los paréntesis

More info:


Hoisting

Se le llama Hoisting al efecto particular que tiene el intérprete interno de separar la definición de una variable en declaración e inicializacion, y de “mover” las declaraciones al principio de la función (aplicandoles el valor undefined)

var joe = “plumber”
// var joe <- declaración
// joe = “plumber” <- inicializacion

Este efecto es particular de javascript y puede producir efectos “inesperados”

var myvar = 'my value';
(function() {
  alert(myvar);
  var myvar = 'local value';
})();
// que valor devolverá el alert??

Es por esto, que se considera una buena practica en Javascript declarar todas las variables al principio de la función

More info:

results matching ""

    No results matching ""