先看下面代码,你是否知道其输出为何?
var foo = 1;
function bar() {
if (!foo) {
var foo = 10;
}
alert(foo);
}
bar();
上一段代码输出为10,你是否觉得惊讶?
var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
alert(a);
而这一段代码输出为1。
上述代码解析
第一段代码为何输出为10,可以把代码解析成如下:
var foo = 1;
function bar() {
var foo; // 由于变量提升,会把foo的声明(declaration)放在if语句之上,function之下。
//因为if并不产生作用域,function才会。此时foo的值为 undefined
if (!foo) { //运行到此时时,(!foo)即(!undefined)为ture,将运行if语句中的语句
foo = 10; //原语句为 var foo = 10; //初始化foo变量,此时foo值为10,
}
alert(foo); //此时的 foo变量并不是第一行声明的foo,而是第三行声明的foo,值为10
}
bar();
假如把第一段代码改成如下,输出为1
var foo = 1;
function bar() {
if (!foo) { // if语句下没有变量声明,所以没有变量提升,if(!foo)中foo为第一行定义的变量,所以foo的值为1
foo = 10; //原语句为 var foo = 10; 因为 (!foo)即(!1)为false,所以这一行并没有执行
}
alert(foo); //输出为1
}
bar();
接下来解析第二段代码,解析过程如下
javascript作用域
在javascript中只有全局作用域和函数(function)作用域。并不存在类似C,C++,JAVA等语言中的块作用域。
在C中,下面代码输出为 1,2,1
#include <stdio.h>
int main() {
int x = 1;
printf("%d, ", x); // 1
if (1) {
int x = 2;
printf("%d, ", x); // 2
}
printf("%d\n", x); // 1
}
但是在Javascript中,下面代码输出为 1,2,2。因为在 if(){ }
块中并不生成新的变量作用域。
var x = 1;
console.log(x); // 1
if (true) {
var x = 2;
console.log(x); // 2
}
console.log(x); // 2
但是函数却生成新的作用域,把上述代码改成如下格式,结果为 1,2,1
function foo() {
var x = 1;
console.log(x);
if (x) {
(function () {
var x = 2;
console.log(x);
// some other code
}());
}
console.log(x);
// x is still 1.
}
参考链接
- js statement vs expression
http://2ality.com/2012/09/expressions-vs-statements.html - JavaScript Scoping and Hoisting
http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html