#javascript #function #scope #hoisting #lexical
#javascript #функция #область видимости #подъем #Лексический
Вопрос:
У меня есть:
// Shouldn't we have the following hoisted?
// var multiply; (undefined)
// var add; (undefined)
var multiply = function(num) {
return add(num) * 2;
};
var add = function(num) {
return num 1;
};
console.log(multiply(1)); // No error, somehow "multiply" calls "add"!
Я думал, что переменные JavaScript поднимаются наверх, но не значения, которым они присвоены. Каким-то образом multiply
вызов add
не возвращает ошибку, даже несмотря на то, что add
она объявлена ниже multiply
.
Комментарии:
1. Я так думаю, основываясь на моей, по общему признанию, ошибочной памяти о чтении этого blog.bitsrc.io / … , которая может научить вас большему, чем вы хотели знать. Основы, которые я помню, включают в себя то, что каждая функция получает свой собственный контекст выполнения, который включает в себя пару внутренних лексических сред (одна из которых специфична для тех идентификаторов, объявленных с помощью
var
), и эти лексические среды могут обращаться к внешней среде. Кроме того, я думаю, что объявленияvar
andfunction
поднимаются, а объявленияlet
andconst
— нет…2. Объяснение довольно простое. JS позволяет вашим функциям ссылаться на переменные, которые не существуют. Таким образом, вероятность ошибки возникает только после вызова функции. Во время вызова, если указанная переменная не существует, вы получаете сообщение об ошибке. В качестве теста удалите
add()
функцию и обновитеmultiply()
, чтобы она использовалаtry/catch
, гдеtry
пытается вызватьadd()
, иcatch
создает ее вwindow.add = function() {...}
. Вы увидите, что ошибка ReferenceError обнаруживается при первом вызове, но последующие вызовы выполняются успешно.3. …вот так: jsfiddle.net/cpzj309w
Ответ №1:
Вы правы в том, что объявления поднимаются наверх, а назначения — нет.
Однако функции не сохраняют значения каких-либо переменных за пределами них с момента их создания. Вместо этого они используют все, что в них есть, когда они вызываются. В этом случае, add
это undefined
когда multiply
функция создана, но ей назначена функция перед multiply
вызовом, поэтому multiply
используется новая назначенная функция.
Чтобы увидеть это более четко, рассмотрим этот код:
var multiply = function(num) {
return add(num) * 2;
};
// Would be an error
// console.log(multiply(1));
var add = function(num) {
return num 1;
};
console.log(multiply(1)); // Prints 4
add = function(num) {
return num 2;
};
console.log(multiply(1)); // Prints 6
Последняя console.log
выводится 6
, потому что multiply использовал новую функцию в add
вместо того, чтобы сохранить ту, которая была у него раньше.