Являются ли функции заданными перед переменными на этапе создания javascript?

Я делаю курс Udemy Javascript: Understanding the Weird Parts прямо сейчас, и я только что узнал о фазе создания и стадии выполнения, происходит, когда интерпретатор интерпретирует JS.

У меня есть вопрос, но я сначала покажу вам код, с которым я играю:

http://codepen.io/rsf/pen/bEgpNY

b();

function b () {

  console.log(a);
}

var a = 'peas';

b();

Если я правильно понимаю, на этапе создания переменные и функции "установлены", то есть им даются пятна в памяти. Все переменные имеют значение placeholder undefined. Затем на этапе выполнения двигатель выполняет строки, начинающиеся с вершины. Когда сначала вызывается b(), "a" все еще имеет значение-заполнитель undefined, тогда "a" получает свое начальное значение "peas", b() вызывается снова, и на этот раз "a" имеет значение "гороха". На мой взгляд, одна из двух вещей должна происходить здесь. Альтернатива 1: На этапе создания все переменные задаются перед функциями. Это означает, что когда создается пространство памяти для функции b(), функция включает значение undefined (поскольку пространство памяти 'a' уже было создано со значением 'undefined'). Альтернатива 2: функции и переменные задаются в лексическом порядке, в котором они находятся (в этом случае b создается до a), а когда b создается, ссылка "a" каким-то образом означает, что функция прослушивает любое возможное создание местоположения памяти "a" , и, когда позднее создается "a" , ссылка ссылается на это место.

Я нахожусь на правильном пути с любым из этих сценариев?

Ответ 1

Вы можете думать об этом так. Ваш исходный код:

b();

function b () {

  console.log(a);
}

var a = 'peas';

b();

выполняется следующим образом:

var a;
function b () {
  console.log(a);
}

b(); // log undefined because a doesn't have a value yet

a = 'peas';

b(); // log peas because a has a value

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

Ответ 2

Если я правильно понимаю, на этапе создания переменные и функции "установлены", то есть им даются пятна в памяти.

Я не использовал бы термин set для этого - он обычно используется для ссылки на переменную, которая задана (назначена) конкретное значение. Я также не буду использовать термин "пятно" или "память" - нам не нужно беспокоиться об этих внутренностях. Это проще сказать объявлено.

Мне также не нравится использование термина "фаза создания", который является нестандартным и запутанным - что именно создается? Я бы предпочел термин "компиляция".

Все переменные имеют значение-заполнитель undefined.

Если быть точным, я бы не сказал, что они "имеют значение undefined", а скорее "не имеют значения" или "не определены". undefined не является значением, удерживаемым переменной, которая еще не назначена; скорее это состояние , что приводит к тому, что переменная оценивается значением undefined при доступе.

Альтернатива 1: На этапе создания все переменные задаются перед функциями.

Да, хотя снова будет запутанно использовать слово "set". Скажем, "все переменные объявляются перед функциями". Это процесс hoisting.

Альтернатива 2: функции и переменные задаются в лексическом порядке, в котором они находятся (в этом случае b создается до a), а когда b создается, ссылка "a" каким-то образом означает, что функция прослушивает любое возможное создание ячейки памяти "a" , и, когда позднее создается "a" , ссылка ссылается на это место.

Нет. Функция не "слушает" что-либо. Он просто выполняет, когда вы это рассказываете.

Это важно?

Не совсем. Он попадает в категорию аркана. Таким образом, мы забиваем мозги такими правилами, как, например, переходы переменных, декларации функций поднимаются каким-то другим способом, let имеет еще какое-то другое подъемное поведение. На практике почти все руководства по стилям потребуют, чтобы вы объявили переменные в верхней части функции, и линтеры будут предупреждать вас, если вы этого не сделаете (или можете настроить для этого). Это немедленно устраняет все проблемы с изменяющимся подъемом.

Некоторым людям нравится помещать внутренние функции в нижнюю часть их функции, и это отлично работает, поскольку, если это объявление функции (т.е. function foo() { }), все это (включая определение) поднимается. Если это выражение функции присваивается переменной (т.е. var foo = function() { }), то это переменная, и мы уже решили поставить ее в верхней части нашей функции - см. Выше.

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

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

(Есть некоторые исключения, такие как объявление переменной внутри оператора for, как в for (var i...), что прекрасно, если i не используется ни для чего иного, кроме индекса цикла.)

По какой-то причине люди, изучающие JS, иногда могут сосредоточиться на этих странностях - например, "почему" " " == false или что-то в этом роде. Вместо этого я хотел бы остановиться на том, как думать о ваших проблемах и разрушать их, и написав хороший чистый код, который просто работает, и что вы и другие люди можете поддерживать, не беспокоясь о Arcana. Я писал JS в течение многих лет и не могу вспомнить, когда в последний раз я столкнулся с проблемой, связанной с подъемом.