Это явление известно как: Подъем переменных JavaScript .
Вы никогда не обращаетесь к глобальной переменной в своей функции; вы всегда обращаетесь только к локальной value
переменной.
Ваш код эквивалентен следующему:
var value = 10;
function test() {
var value;
console.log(value);
value = 20;
console.log(value);
}
test();
Вы все еще удивлены undefined
?
Пояснение:
Это то, с чем рано или поздно сталкивается каждый программист JavaScript. Проще говоря, любые объявленные вами переменные всегда поднимаются на вершину вашего локального замыкания. Таким образом, даже если вы объявили свою переменную после первого console.log
вызова, она по-прежнему считается, как если бы вы объявили ее до этого.
Однако поднимается только часть объявления; с другой стороны, назначение - нет.
Итак, при первом вызове console.log(value)
вы ссылались на локально объявленную переменную, которой еще ничего не назначено; следовательно undefined
.
Вот еще пример :
var test = 'start';
function end() {
test = 'end';
var test = 'local';
}
end();
alert(test);
Как вы думаете, что это предупредит? Нет, не просто читай, думай об этом. Какая ценностьtest
?
Если вы сказали что-нибудь кроме start
, вы ошибались. Приведенный выше код эквивалентен этому:
var test = 'start';
function end() {
var test;
test = 'end';
test = 'local';
}
end();
alert(test);
так что глобальная переменная никогда не затрагивается.
Как видите, независимо от того, где вы помещаете объявление переменной, оно всегда поднимается в верхнюю часть вашего локального закрытия.
Примечание:
Это также относится к функциям.
Рассмотрим этот фрагмент кода :
test("Won't work!");
test = function(text) { alert(text); }
что даст вам справочную ошибку:
Uncaught ReferenceError: тест не определен
Это сбивает с толку многих разработчиков, поскольку этот фрагмент кода отлично работает:
test("Works!");
function test(text) { alert(text); }
Причина этого, как указано, в том, что часть назначения не поднимается. Итак, в первом примере при test("Won't work!")
запускеtest
переменная уже была объявлена, но ей еще не назначена функция.
Во втором примере мы не используем присвоение переменных. Скорее всего , мы используем правильный синтаксис объявления функции, которая делает получить функцию полностью водрузили.
Бен Черри написал отличную статью по этому поводу под соответствующим названием JavaScript Scoping and Hoisting .
Прочтите это. Это даст вам полную картину во всех деталях.
Меня несколько разочаровало объяснение проблемы, но никто не предложил решения. Если вы хотите получить доступ к глобальной переменной в области функции без функции, которая сначала создает неопределенную локальную переменную, укажите на переменную как
window.varName
источник
Переменные в JavaScript всегда имеют область действия на уровне всей функции. Даже если они были определены в середине функции, они видны раньше. Подобные явления могут наблюдаться при подъеме функций.
При этом первый
console.log(value)
видитvalue
переменную (внутреннюю, которая затеняет внешнююvalue
), но она еще не инициализирована. Вы можете думать об этом так, как если бы все объявления переменных были неявно перемещены в начало функции (а не в самый внутренний блок кода), а определения оставлены на том же месте.Смотрите также
источник
Есть глобальная переменная
value
, но когда вtest
функцию входит управление ,value
объявляется другая переменная, которая затеняет глобальную. Поскольку объявления переменных ( но не присваивания ) в JavaScript поднимаются в верхнюю часть области видимости, в которой они объявлены://value == undefined (global) var value = 10; //value == 10 (global) function test() { //value == undefined (local) var value = 20; //value == 20 (local) } //value == 10 (global)
Обратите внимание, что то же самое верно и для объявлений функций, что означает, что вы можете вызвать функцию до того, как она будет определена в вашем коде:
test(); //Call the function before it appears in the source function test() { //Do stuff }
Также стоит отметить, что когда вы объединяете их в выражение функции, переменная будет находиться
undefined
до тех пор, пока не произойдет присвоение, поэтому вы не можете вызвать функцию, пока это не произойдет:var test = function() { //Do stuff }; test(); //Have to call the function after the assignment
источник
Самый простой способ сохранить доступ к внешним переменным (не только к глобальным) - это, конечно, попытаться не объявлять их повторно под тем же именем в функциях; просто не используйте там var . Рекомендуется использовать правильные описательные правила именования . С ними будет сложно получить переменные, названные как value (этот аспект не обязательно связан с примером в вопросе, поскольку это имя переменной могло быть дано для простоты).
Если функция может быть повторно использована в другом месте и, следовательно, нет гарантии, что внешняя переменная действительно определена в этом новом контексте, можно использовать функцию Eval . Эта операция выполняется медленно, поэтому ее не рекомендуется использовать для функций, требующих высокой производительности:
if (typeof variable === "undefined") { eval("var variable = 'Some value';"); }
Если переменная внешней области видимости, к которой вы хотите получить доступ, определена в именованной функции, тогда она может быть прикреплена к самой функции в первую очередь, а затем доступна из любого места в коде - будь то из глубоко вложенных функций или обработчиков событий вне все остальное. Обратите внимание, что доступ к свойствам намного медленнее и потребует от вас изменения способа программирования, поэтому это не рекомендуется, если это действительно не нужно: Переменные как свойства функций (JSFiddle) :
// (the wrapper-binder is only necessary for using variables-properties // via "this"instead of the function's name) var functionAsImplicitObjectBody = function() { function someNestedFunction() { var redefinableVariable = "redefinableVariable's value from someNestedFunction"; console.log('--> functionAsImplicitObjectBody.variableAsProperty: ', functionAsImplicitObjectBody.variableAsProperty); console.log('--> redefinableVariable: ', redefinableVariable); } var redefinableVariable = "redefinableVariable's value from someFunctionBody"; console.log('this.variableAsProperty: ', this.variableAsProperty); console.log('functionAsImplicitObjectBody.variableAsProperty: ', functionAsImplicitObjectBody.variableAsProperty); console.log('redefinableVariable: ', redefinableVariable); someNestedFunction(); }, functionAsImplicitObject = functionAsImplicitObjectBody.bind(functionAsImplicitObjectBody); functionAsImplicitObjectBody.variableAsProperty = "variableAsProperty's value, set at time stamp: " + (new Date()).getTime(); functionAsImplicitObject(); // (spread-like operator "..." provides passing of any number of arguments to // the target internal "func" function in as many steps as necessary) var functionAsExplicitObject = function(...arguments) { var functionAsExplicitObjectBody = { variableAsProperty: "variableAsProperty's value", func: function(argument1, argument2) { function someNestedFunction() { console.log('--> functionAsExplicitObjectBody.variableAsProperty: ', functionAsExplicitObjectBody.variableAsProperty); } console.log("argument1: ", argument1); console.log("argument2: ", argument2); console.log("this.variableAsProperty: ", this.variableAsProperty); someNestedFunction(); } }; return functionAsExplicitObjectBody.func(...arguments); }; functionAsExplicitObject("argument1's value", "argument2's value");
источник
Я столкнулся с той же проблемой даже с глобальными переменными. Я обнаружил, что моя проблема заключалась в том, что глобальная переменная не сохраняется между HTML-файлами.
<script> window.myVar = 'foo'; window.myVarTwo = 'bar'; </script> <object type="text/html" data="/myDataSource.html"></object>
Я попытался сослаться на myVar и myVarTwo в загруженном HTML-файле, но получил неопределенную ошибку. Короче говоря, я обнаружил, что могу ссылаться на переменные, используя:
<!DOCTYPE html> <html lang="en"> <!! other stuff here !!> <script> var myHTMLVar = this.parent.myVar /* other stuff here */ </script> </html>
источник