Почему это странное поведение?
Я изменяю часть кода тремя способами. В этих трех условиях поведение ведет себя по-разному. Опишите, как это выполняется?
var a=1;
function myFunc(){
console.log(a);
console.log(a)
}
myFunc();
//Output is:
1
1
var a=1;
function myFunc(){
console.log(a);
var a=2;
console.log(a)
}
myFunc();
//Output is:
undefined
2
var a=1;
function myFunc(){
console.log(a);
var a=2;
console.log(a)
}
myFunc(a);
//Output is:
undefined
2
Почему во втором случае он печатает undefined? И в 3-м случае я отправляю свой глобальный как аргумент, затем также печатаю undefined.
Ответы
Ответ 1
Это потому, что JavaScript перемещает объявления var в начало области, поэтому ваш код на самом деле:
var a = 1;
function myFunc(){
var a; // a is redeclared, but no value is assigned
console.log(a); // therefore it evaluates to undefined
a = 2; // now a = 2
console.log(a); // and then it logs to 2
}
myFunc();
Это поведение называется Variable Подъем.
ИЗМЕНИТЬ
Как сказал Beterraba, в третьем коде он записывает undefined
, потому что в заголовке функции не было объявлено никаких аргументов:
var a = 1;
function myFunc(a) { // a is declared
console.log(a); // now a logs 1
var a = 2; // now a = 2
console.log(a);
}
myFunc(a);
Ответ 2
Второй случай - печать undefined из-за того, как работает контекст JavaScript Execution. Возможно, вы столкнулись с термином hoisting.
Чтобы объяснить это более подробно, при вызове второй функции интерпретатор войдет в процесс с двумя фазами.
Стадия создания
- Создает цепочку областей действия
- Создает аргументы, функции, переменные, так называемый объект переменной
- Определяет значение "this" ключевое слово
Активация или этап выполнения кода
- интерпретирует и выполняет код
Поэтому, когда вы вызываете myFunc()
, интерпретатор JavaScript создает контекст выполнения, который вы можете рассматривать как литерал объекта, который выглядит так:
myFuncExecutionContext = {
scopeChain: { ... },
variableObject: {
arguments: {
length: 0
},
a: undefined,
},
this: { ... }
}
Вы можете видеть, что локальная переменная имеет начальное значение undefined. На этапе выполнения кода интерпретатор будет запускать функцию по строкам; Итак, первая строка, которую он видит, - console.log(a);
. Интерпретатор будет смотреть на variableObject
, чтобы увидеть, есть ли переменная с этим именем. Если нет, то он будет использовать цепочку областей видимости и попытается найти ее в переменном объекте внешних областей. Поскольку в объекте переменной есть переменная a
, она будет читать ее значение, которое равно undefined.
Тогда это будет сделано в строке 2, где будет присваиваться значение локальной переменной a; var a=2;
. Затем он выполнит последнюю строку - console.log(a)
-, которая выведет значение, которое мы назначили ранее.
Тот же механизм оправдывает, почему мы можем вызывать функцию до ее определения, если мы используем синтаксис объявления функции.
someFunc(); // VALID
function someFunc(){ };
В то время как следующее приведет к ошибке:
someFunc(); // TypeError: undefined is not a function
var someFunc = function() { }