Подтвердить что ты не робот

Необходимо понять пример использования функции Javascript

Я прочитал концепцию Javascript Hoisting.Its довольно запутанный, но я увидел несколько примеров и понял, что на самом деле делает подъем.

Итак, в основном " Подъем - это поведение JavaScript по умолчанию для перемещения всех объявлений в верхнюю часть текущей области (вверху текущей script или текущей функции)."

Но я не могу понять следующую реализацию:

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

В окне предупреждения отображается " Я НЕ Android".

Я хочу знать, почему foo() вызывается из блока else, даже если значение is_android равно true.

Любая помощь будет оценена.

4b9b3361

Ответ 1

tl; dr: Не используйте что-то, что выглядит как объявление функции внутри блока, особенно не условное.


Фактически, большинство браузеров неправильно интерпретируют этот фрагмент кода. Они рассматривают определения функций как функции объявления, хотя декларации функций не допускаются внутри блоков, поскольку объявление функции не, это исходный элемент.

Как это работает вообще:

Прежде чем код будет выполнен, интерпретатор ищет объявления all переменных и функций, независимо от того, где они находятся, и создает привязку для них в текущей/новой среде. Затем он начинает выполнять код.

Итак, предполагая, что определения функций интерпретируются как объявления, так как есть два объявления, последний выигрывает. Ваш код в основном будет:

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

is_android = true;
if (is_android) {

} else {

}
foo();

Другие двигатели интерпретируют это по-другому, но все же неправильно (IMO, см. ниже):

В следующем script нулевая функция никогда не определяется и не может быть вызвана, потому что 'if (0)' оценивает ее условие на false:

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

Примечание. Некоторые движки JavaScript, не включая SpiderMonkey, неправильно обрабатывают любое выражение функции с именем в качестве определения функции. Это приведет к определению нуля, даже при условии всегда ложного условия. Более безопасный способ условного определения функций - анонимно определить функцию и присвоить ее переменной:

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

Но в этом случае, если определение функции действительно интерпретировалось как выражение функции (аналогично (function zero() { ... })), то имя функции не будет доступно в области содержимого, а функция будет просто потеряна.

Ответ 2

В Javascript есть тонкие различия между двумя похожими типами

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

и

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

Самое большое различие заключается в том, что в первом случае назначение объекта функции имени square выполняется при вводе области, а не при достижении линии. Это позволяет вызывать функции, которые определены позже в исходном коде... например:

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

- это действительный script, который будет работать, даже если вызов происходит "до" определения функции (и, кстати, разрешая этот тип кода ИМО, причиной того, что правило находится на языке).

Во втором случае вместо этого присваивание является просто регулярным оператором и выполняется, когда (и если) поток управления проходит через него.

Если вы хотите, чтобы этот фрагмент работал так, как вы ожидаете, просто измените код из

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

к

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

PS: вы можете повторить имя также во второй форме, но это обычно не выполняется, и вместо этого используются анонимные функции.

Ответ 3

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

Это лучшая статья, которую я прочитал о том, что вы убираете.

Объявления, имена и подхватывание

В JavaScript имя входит в область действия одним из четырех основных способов:

Определяется по языку: все области по умолчанию заданы имена this и arguments. Формальные параметры: функции могут иметь имена формальных параметров, которые привязаны к телу этой функции. Объявление функций: они имеют форму function foo() {}. Объявления переменных: они принимают форму var foo;. Объявления функций и объявления переменных всегда перемещаются ( "поднимаются" ) невидимо в верхнюю часть их области с помощью интерпретатора JavaScript. Функциональные параметры и языковые имена, очевидно, уже есть. Это означает, что код такой:

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

фактически интерпретируется следующим образом:

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

Оказывается, не имеет значения, будет ли выполняться строка, содержащая объявление. Следующие две функции эквивалентны:

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

Обратите внимание, что часть присваивания деклараций не была поднята. Только имя поднимается. Это не относится к объявлениям функций, в которых также будет поднято тело всей функции. Но помните, что есть два обычных способа объявления функций. Рассмотрим следующий 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();

В этом случае только объявление функции имеет свое тело, поднятое вверх. Имя "foo" поднято, но тело остается позади, которое должно быть назначено во время выполнения.

Это охватывает основы подъема, что не так сложно или запутанно, как кажется. Конечно, это JavaScript, в некоторых особых случаях немного сложнее.

Ответ 4

Возможно, вы уже понимаете способ объявления функций, чтобы избежать подъема, но в случае не: вы можете записать его как:

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

и foo() не будут оцениваться до тех пор, пока интерпретатор javascript не проверит условное утверждение.

Ответ 5

вы смешиваете понятия.

Начните с этого кода:

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

Это не даст ошибки. Вместо этого просто предупреждения 2. Поскольку второе определение foo() переопределяет первый.

Попробуйте следующий код:

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

Это приведет к ложному срабатыванию. Несмотря на то, что foo определяется внутри блока, который не выполняется (if if false), объявления функций всегда обрабатываются JavaScript.

С учетом этих двух примеров легко понять, что происходит в вашем коде: вы дважды определяете функцию foo, а второе определение переопределяет первое.

То, что вы пытались в вашем коде, очень близко к "условной компиляции", и это поведение можно моделировать в JavaScript, объявляя функции как переменные:

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

Этот код просто предупреждает true. Обратите внимание, что теперь foo определяется как переменная (содержащая функцию, но переменную).

Привет