Почему я могу использовать функцию до ее определения в JavaScript?

Этот код всегда работает даже в разных браузерах:

function fooCheck() {
  alert(internalFoo()); // We are using internalFoo() here...

  return internalFoo(); // And here, even though it has not been defined...

  function internalFoo() { return true; } //...until here!
}

fooCheck();

Я не мог найти ни одной ссылки на то, почему он должен работать. Я впервые увидел это в записке Джона Ресига, но об этом только упоминалось. Там нет объяснений там или где-то в этом отношении.

Может кто-нибудь, пожалуйста, просветит меня?

Ответ 1

Объявление function является магическим и приводит к привязке его идентификатора до того, как будет выполняться что-либо в его кодовом блоке.

Это отличается от присваивания выражением function, которое оценивается в нормальном порядке сверху вниз.

Если вы изменили пример, чтобы сказать:

  var internalFoo = function() {return true; };
Код>

он перестанет работать.

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

Это описано в стандарте ECMAScript, раздел 10.1.3. К сожалению, ECMA-262 не очень читаемый документ даже по стандартам!

*: содержащая функция, блок, модуль или script.

Ответ 2

Браузер читает ваш HTML от начала до конца и может выполнять его, поскольку он считывается и анализируется в исполняемые фрагменты (объявления переменных, определения функций и т.д.). Но в любой момент можно использовать только то, что было определено в html до этого точка.

Это отличается от других контекстов программирования, которые обрабатывают (компилируют) весь исходный код, связывают его вместе с любыми необходимыми библиотеками и строят исполняемый модуль, с которого начинается выполнение.

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

Когда вы познакомитесь с JavaScript, вы осознаете свою потребность писать вещи в правильной последовательности.

Версия: Чтобы подтвердить принятый ответ (см. выше), используйте Firebug для перехода через раздел script веб-страницы. Вы увидите, что он пропускает функцию в функцию, посещая только первую строку, прежде чем она действительно выполнит любой код.

Ответ 3

Он называется HOISTING - вызывать (вызывать) функцию до того, где она была определена.

Два разных типа функций, о которых я хочу написать, следующие:

Функции выражения и функции замедления

  • Функции выражения:

    Выражение функции может быть сохранено в переменной, поэтому им не нужны имена функций. Они также будут называться анонимной функцией (функция без имени).

    Чтобы вызывать (вызывать), они всегда нуждаются в использовании имени переменной . Эти функции не будут работать, если вызовы до того момента, когда они были определены, что означает, что здесь не происходит подъем. Мы всегда должны сначала определить функцию выражения, а затем вызвать его.

    let lastName = function (family) {
     console.log("My last name is " + family);
    };
    let x = lastName("Lopez");
    

    Вот как вы можете писать в ECMAScript 6:

    lastName = (family) => console.log("My last name is " + family);
    
    x = lastName("Lopez");
    
  • Функции замедления:

    Функции, объявленные с помощью следующего синтаксиса, не выполняются немедленно. Они "сохраняются для последующего использования" и будут выполняться позже, когда они будут вызваны (вызваны). Эти типы функций работают, если вы называете их ПЕРЕД или ПОСЛЕ того, где они были определены. Если вы вызываете функцию замедления до того, где она была определена - Подъем - работает правильно.

    function Name(name) {
      console.log("My cat name is " + name);
    }
    Name("Chloe");
    

    Пример подъема:

    Name("Chloe");
    function Name(name) {
       console.log("My cat name is " + name);
    }
    

Ответ 5

В некоторых языках есть требование, чтобы идентификаторы были определены перед использованием. Причиной этого является то, что компилятор использует один проход на исходном коде.

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

Ответ 6

Тело функции "internalFoo" должно идти куда-то во время разбора, поэтому, когда код считывается (ака разбора) интерпретатором JS, создается структура данных для функции и назначается имя.

Только позже, тогда код запускается, JavaScript действительно пытается выяснить, существует ли "internalFoo" и что это такое, и можно ли его вызывать и т.д.

Ответ 7

По той же причине в глобальном пространстве имен всегда будет помещаться foo:

if (test condition) {
    var foo;
}