Necesidad de entender el ejemplo de elevación de la función Javascript


He leído el concepto de Javascript Hoisting.Es bastante confuso, pero vi algunos ejemplos y tuve la idea de lo que realmente hace el levantamiento.

Así que básicamente " Hoisting es el comportamiento predeterminado de JavaScript de mover todas las declaraciones a la parte superior del ámbito actual (a la parte superior del script actual o la función actual)."

Pero no soy capaz de entender la siguiente implementación:

var is_android = true;
if (is_android) {
    function foo() {
        alert('I am Android');
    }
} else {
    function foo() {
        alert('I am NOT Android');
    }
}
foo();

La salida muestra "NO soy Android" en alerta cuadro.

Quiero saber por qué se llama a foo() desde el bloque else incluso si el valor de is_android es true .

Cualquier ayuda será apreciada.

Author: Siddharth_Vyas, 2014-04-17

5 answers

Tl; dr: No use algo que se parezca a una función declaración dentro de un bloque, especialmente no un condicional.


El hecho es que la mayoría de los navegadores interpretan este fragmento de código de manera incorrecta. Tratan las definiciones de función como declaraciones de función , aunque las declaraciones de función no están permitidas dentro de bloques, ya que una declaración de función es no una declaración , es un elemento fuente.

Este cómo funciona en general:

Antes de que el código sea ejecutado, el intérprete busca todas las declaraciones de variables y funciones, no importa donde están, y crea un enlace para ellas en el entorno actual/nuevo. Entonces comienza a ejecutar el código.

Por lo tanto, suponiendo que las definiciones de función se interpretan como declaraciones, ya que hay dos declaraciones, la última gana. Su código básicamente se convierte en:

function foo() {
    alert('I am Android');
}
function foo() {
    alert('I am NOT Android');
}
var is_android;

is_android = true;
if (is_android) {

} else {

}
foo();

Otros motores sería interpretarlo de manera diferente , pero todavía incorrectamente (OMI, ver más abajo):

En el siguiente script, la función zero nunca se define y no se puede invocar, porque 'if (0)' evalúa su condición a false:

if (0) {
   function zero() {
      document.writeln("This is zero.");
   }
}

Nota: Algunos motores JavaScript, sin incluir SpiderMonkey, tratan incorrectamente cualquier expresión de función con un nombre como una definición de función. Esto llevaría a que se definiera cero, incluso con la condición if siempre falsa. Una forma más segura de definir funciones condicionalmente es definir la función de forma anónima y asignarla a una variable:

if (0) {
   var zero = function() {
      document.writeln("This is zero.");
   }
}

Pero en este caso, si la definición de la función realmente se interpretó como expresión de función (de manera similar a (function zero() { ... })), entonces el nombre de la función no sería accesible en el ámbito contenedor, y la función simplemente se perdería.

 21
Author: Felix Kling,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-17 06:19:18

En Javascript hay diferencias sutiles entre los dos

 function square(x) { return x*x; }

Y

 var square = function(x) { return x*x; }

La mayor diferencia es que en el primer caso la asignación del objeto de función al nombre square se realiza al entrar en el ámbito, no al llegar a la línea. Esto permite llamar a funciones que se definen más adelante en el código fuente... por ejemplo:

console.log(cube(12));
function cube(x) { return x*x*x; }

Es un script válido que funcionará, incluso si la llamada ocurre "antes" de la definición de la función (y, por la manera, permitiendo este tipo de código es IMO la razón de la regla que está en el idioma).

En el segundo caso, la asignación es solo una instrucción regular y se ejecuta cuando (y si) el flujo de control pasa a través de ella.

Si desea que ese fragmento funcione como espera, simplemente cambie el código de

function <name> (...) { ... }

A

var <name> = function (...) { ... }

PD: puede repetir el nombre también en la segunda forma, pero normalmente no se hace y se usan funciones anónimas en su lugar.

 5
Author: 6502,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-17 06:02:24

Http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html

Este es el mejor artículo que he leído sobre alojamiento.

Declaraciones, Nombres y Elevación

En JavaScript, un nombre entra en un ámbito de una de cuatro maneras básicas:

Definido por el lenguaje: Todos los ámbitos tienen, por defecto, los nombres this y arguments. Parámetros formales: Las funciones pueden tener parámetros formales con nombre, que se circunscriben al cuerpo de esa función. Declaraciones de funciones: Estos son de la función de forma foo () {}. Declaraciones de variables: Estas toman la forma var foo;. Las declaraciones de funciones y las declaraciones de variables son siempre movidas ("izadas") invisiblemente a la parte superior de su ámbito contenedor por el intérprete JavaScript. Los parámetros de las funciones y los nombres definidos por el idioma, obviamente, ya están allí. Esto significa que el código como este:

function foo() {
    bar();
    var x = 1;
}

En realidad se interpreta así:

function foo() {
    var x;
    bar();
    x = 1;
}

Resulta que no importa si la línea que contiene la declaración se ejecutaría alguna vez. Las dos funciones siguientes son equivalentes:

function foo() {
    if (false) {
        var x = 1;
    }
    return;
    var y = 1;
}
function foo() {
    var x, y;
    if (false) {
        x = 1;
    }
    return;
    y = 1;
}

Observe que la parte de asignación de las declaraciones no se izó. Sólo el nombre es ho. Este no es el caso con las declaraciones de función, donde también se izará todo el cuerpo de la función. Pero recuerde que hay dos formas normales de declarar funciones. Considere el siguiente JavaScript:

function test() {
    foo(); // TypeError "foo is not a function"
    bar(); // "this will run!"
    var foo = function () { // function expression assigned to local variable 'foo'
        alert("this won't run!");
    }
    function bar() { // function declaration, given the name 'bar'
        alert("this will run!");
    }
}
test();

En este caso, solo la declaración de función tiene su cuerpo elevado a la superior. El nombre 'foo' se ho, pero el cuerpo se deja atrás, para ser asignado durante la ejecución.

Que cubre los conceptos básicos de elevación, que no es tan complejo o confuso como parece. Por supuesto, al ser JavaScript, hay un poco más de complejidad en ciertos casos especiales.

 3
Author: ProllyGeek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-17 05:51:31

Es posible que ya entienda la forma de declarar las funciones para evitar la elevación, pero en caso de que no: puedes escribirlo como:

var is_android = true;
if (is_android) {
    var foo = function() {
        alert(5);
    };
} else {
    var foo = function() {
        alert(7);
    };
}
foo();

Y foo() no serán evaluados hasta que el intérprete javascript haya evaluado la sentencia condicional.

 3
Author: LexJacobs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-17 05:59:09

Estás mezclando conceptos.

Comience con este código:

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

Esto no dará error. En su lugar solo alertas 2. Porque la segunda definición de foo() anula la primera.

Intente ahora el siguiente código:

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

Esto solo alertará a false. Aunque foo está definido dentro de un bloque que no se ejecuta (un si false) las declaraciones de función siempre son procesadas por JavaScript.

Con estos dos ejemplos en mente es fácil entender lo que sucede en su código: Se define dos veces una función foo, y la segunda definición anula la primera.

Lo que estabas intentando en tu código es algo muy cercano a la "compilación condicional"y este comportamiento se puede simular en JavaScript declarando funciones como variables:

if (true) {
    var foo = function() {alert ('true');}
}
else {
    var foo = function() {alert ('false');}
}
foo(); 

Este código solo alerta true. Tenga en cuenta que ahora foo se define como una variable (que contiene una función, pero una variable).

Saludos

 2
Author: eiximenis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-17 06:00:19