Порядок функций в JavaScript

Мой вопрос основан на примере из книги " Объектно-ориентированный JavaScript" (стр. 81 - Lexical Scope)

Итак, я понимаю из этого примера...

function f1(){var a = 1; f2();}
function f2(){return a;}
f1();

... тот:

а не определено

Но как f1 узнать о f2, который определяется после f1?

Такое поведение вызывает вопрос:

Как работает интерпретатор JavaScript?

Я предполагаю, что это:

  1. сканирует код и просто сохраняет функции, не назначенные ни одной переменной, в глобальной среде
  2. Вызывает функцию в режиме ad-hoc: если такой функции нет в глобальной среде, тогда жаловаться.

2 ответа

Решение

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

Итак, в вашем коде такие вещи происходят (в следующем порядке):

  1. "Переменный объект" создается для контекста выполнения.
  2. Записи (на самом деле, буквально, свойства) в "переменном объекте" создаются для каждого var и объявление функции в контексте (плюс несколько других вещей). В вашем случае это f1 а также f2, Изначально свойства имеют значение undefined,
  3. Все объявления функций обрабатываются, и так:
    • f1 Функция определяется и присваивается своему свойству объекта переменной.
    • f2 Функция определяется и присваивается своему свойству объекта переменной.
  4. f1(); строка выполняется, вызывая f1 функция.
  5. f1 код относится к f2, который он получает от объекта переменной, и поэтому это то, что мы ожидаем, что это будет (ссылка на f2 функция).

Более интересная версия такова:

f1();
function f1(){var a = 1; f2();}
function f2(){return a;}

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

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

var f2 = function() {
};

или это

setTimeout(function() {
    alert("Hi there");
}, 1000);

Обратите внимание, что мы используем результат function оператор как правое значение (в присваивании или путем передачи его в функцию). Они не обрабатываются предварительно при входе в контекст выполнения (например, не на шаге 3 выше), они обрабатываются, когда поток кода достигает их. Что приводит к:

f1();
function f1(){var a = 1; f2();}
var f2 = function(){return a;};

... что не получается, потому что f2 не определено на момент, когда он вызывается.

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

alert("Beginning");
function foo() { ... }
setTimeout(foo, 100);

Это происходит в следующем порядке:

  1. foo создается (так как это определяется объявлением).
  2. alert пробеги.
  3. setTimeout пробеги.
  4. (Потом) foo называется.

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

var f = function foo() { ... }; // <== DON'T DO THIS

Или же

setTimeout(function foo() {     // <== DON'T DO THIS
}, 1000);

Internet Explorer, в частности, имеет проблемы с ними, а также другие реализации в разное время.

Больше для изучения:

У вас нет доступа к переменной 'a' внутри функции f1, потому что функция f2 не определена в области видимости f1

если вы определяете f2 внутри f1:

function f1(){function f2(){return a;} var a = 1; f2();}
f1();

у тебя нет проблем

Другие вопросы по тегам