var foo=1;
function bar(){
foo=10;
return;
function foo(){}
}
bar();
alert(foo);
我目前正在学习javascript在机器中的实际运行方式,以下是我在例子中看到的一段代码。我不知道为什么最终的警报是1而不是10。所以我想知道是否有人能帮我解释javascript虚拟机是如何执行这些代码的。谢谢!
var foo=1;
function bar(){
foo=10;
return;
function foo(){}
}
bar();
alert(foo);
我目前正在学习javascript在机器中的实际运行方式,以下是我在例子中看到的一段代码。我不知道为什么最终的警报是1而不是10。所以我想知道是否有人能帮我解释javascript虚拟机是如何执行这些代码的。谢谢!
这是由于函数声明提升而导致的:
var foo=1;
function bar(){
function foo(){} // This gets moved up here by the engine
foo=10; // You've reassigned the local `foo` function to 10,
// leaving the global `foo` untouched
return;
}
bar();
alert(foo); // Since the foo has never changed in this scope, it's still 1
我不知道为什么最终的警报是1而不是10。
因为在bar
中的这一行中的foo
:
foo = 10;
function foo(){}
...不是在bar
之外的foo
。也就是说:
var foo=1;
function bar(){
foo=10; // <== This `foo`
return;
function foo(){} // <== Is the `foo` declared here
}
bar();
alert(foo);
...不是指向包含作用域中声明的foo
(var foo
)。
这种情况发生的原因有两个:
函数声明在进入包含作用域(在本例中是调用bar
)时立即处理,而不是在函数中逐步处理代码之前。这有时被称为“提升”声明(因为它们发生得就像在顶部一样)。由于函数声明不是逐步执行的代码,因此return
对其是否被处理没有影响;它在return
发生之前被处理。
函数声明还创建了可以看作是具有函数名称的变量。因此,在函数声明中的foo
有效地成为该名称的变量(更多详细信息请参见下文),并且正如您在该代码中看到的那样,您可以将新值分配给这些“变量”。
当运行该代码时,JavaScript引擎执行以下操作:
创建名为foo
的变量,并为其赋初始值undefined
。
创建函数bar
,将bar
添加为当前作用域内的符号(有效地是变量),并将其作为对bar
函数的引用。
开始该范围的逐步代码。
将值1
分配给foo
。
调用bar
函数。
创建与调用bar
相关的foo
函数,将foo
添加为调用期间的符号(有效地是变量),并将其作为对该函数的引用。
开始该范围的逐步代码。
将值10
分配给本地foo
(原来是指向该函数的)。
从函数中返回。
使用该作用域中的foo
调用alert
,它仍然具有值1
。
您可以在规范的§10.4.3节和其链接的部分中了解所有详细信息。
function foo
本质上只是 var foo = function ..
的另一种语法,所以在 bar
中,名称 foo
不是指外部的 foo
变量,而是指本地定义的 foo
。 这个 foo
最初是一个函数,但后来被 10
覆盖。foo
在代码执行之前在解析时就被“保留”并作用域化。从本质上讲,它像这样执行:function bar(){
var foo = function () {};
foo = 10;
return;
}
bar
内声明foo
被_移动_到顶部,那么应用相同的行为,bar
的声明不是会被移动到var foo=1;
之前吗?(这是一个真正的问题,不是修辞问句) - Ejazfunction bar()
之前调用了bar()
,代码仍将成功执行。 - CodingIntrigue