que - Necesidad de entender el ejemplo de elevación de la función Javascript
historia de javascript (5)
En Javascript hay diferencias sutiles entre los dos similares
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 del square
se realiza al ingresar el alcance, no al alcanzar 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 cierto, permitir que este tipo de código sea IMO es la razón por la cual la regla está en el idioma).
En el segundo caso, en cambio, la asignación es solo una declaración regular y se ejecuta cuando (y si) el flujo de control pasa a través de ella.
Si desea que el fragmento funcione como usted 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 en su lugar se utilizan funciones anónimas.
Leí el concepto de Javascript Hoisting. Es bastante confuso, pero vi algunos ejemplos y se me ocurrió lo que realmente hace el izamiento.
Así que, básicamente, " Elevar es el comportamiento predeterminado de JavaScript de mover todas las declaraciones a la parte superior del alcance actual (a la parte superior de la secuencia de comandos actual o la función actual) " .
Pero no puedo 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 el cuadro de alerta.
Quiero saber por qué se llama a foo()
desde otro bloque, incluso si el valor de is_android
es verdadero.
Cualquier ayuda será apreciada.
Es posible que ya entienda la forma de declarar las funciones para evitar la elevación, pero en caso contrario, puede escribirlo como:
var is_android = true;
if (is_android) {
var foo = function() {
alert(5);
};
} else {
var foo = function() {
alert(7);
};
}
foo();
y foo () no se evaluarán hasta que el intérprete de javascript haya evaluado la declaración condicional.
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. Debido a que la segunda definición de foo () anula la primera.
Intenta ahora siguiendo el código:
if (false) {
function foo() { alert(''false'');}
}
foo();
Esto solo alertará a falso. Aunque foo está definido dentro de un bloque que no se ejecuta (y si es falso), las declaraciones de funciones siempre son procesadas por JavaScript.
Con estos dos ejemplos en mente, es fácil entender lo que sucede en su código: usted define dos veces una función foo, y la segunda definición anula la primera.
Lo que intentabas en tu código es algo muy parecido 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 de verdad. Tenga en cuenta que ahora foo se define como una variable (que contiene una función, pero una variable).
Saludos
http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html
Este es el mejor artículo que he leído sobre hositing.
Declaraciones, nombres y levantamiento
En JavaScript, un nombre entra en un ámbito en una de cuatro formas básicas:
Definido por idioma: todos los ámbitos son, por defecto, dados los nombres y argumentos. Parámetros formales: las funciones pueden tener parámetros formales nombrados, que se encuentran dentro del alcance de esa función. Declaraciones de funciones: Estas son de la función de formulario foo () {}. Declaraciones de variables: toman la forma var foo ;. Las declaraciones de funciones y las declaraciones de variables siempre son movidas ("elevadas") de manera invisible por el intérprete de JavaScript. Los parámetros de función y los nombres definidos por el idioma están, 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á alguna vez. Las siguientes dos funciones 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;
}
Tenga en cuenta que la porción de asignación de las declaraciones no se elevó. Sólo el nombre es izado. Este no es el caso de las declaraciones de funciones, donde también se levantará todo el cuerpo de la función. Pero recuerda 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 parte superior. El nombre ''foo'' es izado, pero el cuerpo se queda atrás, para ser asignado durante la ejecución.
Eso cubre los conceptos básicos de la 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.
tl; dr: No use algo que parezca una declaración de función dentro de un bloque, especialmente no es condicional.
El hecho es que la mayoría de los navegadores interpretan esta pieza 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 no es una declaración , es un elemento fuente .
Así funciona en general:
Antes de que se ejecute el código, el intérprete busca todas las declaraciones de variables y funciones, sin importar dónde se encuentren, y crea un enlace para ellas en el entorno actual / nuevo. Entonces comienza realmente ejecutando el código.
Entonces, suponiendo que las definiciones de funciones 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 lo interpretarían de manera diferente , pero aún incorrectamente (OMI, ver más abajo):
En la siguiente secuencia de comandos, la función cero nunca se define y no se puede invocar, porque ''if (0)'' evalúa su condición a falso:
if (0) { function zero() { document.writeln("This is zero."); } }
Nota: Algunos motores de 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 siempre falsa if. 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 fue realmente interpretada como expresión de la función (de manera similar a (function zero() { ... })
), entonces el nombre de la función no sería accesible en el ámbito que lo contiene, y la función solo perderse