4.1 变量提升
console.log(a);//<--理解为什么是undefined而不是2,也不是ReferenceError异常。
var a=2;
引擎会在解释JavaScript代码之前首先对其进行编译,编译阶段中的一部分工作就是找到所有的声明,并用合适的作用域将它们关联起来。
包括变量和函数在内的所有声明都会在任何代码被执行前首先被处理。
例如 var a = 2;JavaScript在处理时会当做两个声明来处理
- var a; 在编译阶段进行;
- a = 2;在原地等待执行阶段;
值得注意的是,函数声明会被提升,但是函数表达式不会。
foo();//不是ReferenceError,而是TypeError
bar();//ReferenceError
var foo = function bar(){
//...
}
由于foo是一个函数表达式,而不是一个函数声明(不以function开头作为第一个词),所以提升时并没有赋值,以上代码可以理解为:
var foo;
foo(); //TypeError
bar(); //ReferenceError
foo = function() {
var bar = ..self..
//...
}
4.2 函数优先
函数声明和变量声明都会提升,但是函数首先被提升,然后才是变量,函数声明会被提升到普通变量之前。
尽管重复的var声明会被忽略,但是出现在后面的函数声明还是可以覆盖掉前面的。
foo(); //3
function foo() {
console.log(1);
}
var foo = function() {
console.log(2);
}
function foo() {
console.log(3);
}
4.3 小结
var a = 2; 对于JavaScript引擎来说是两个单独的声明,第一个是编译阶段的任务,第二个则是执行阶段的任务。
这意味着无论作用域的声明出现在什么地方,都将在代码本身被执行前首先进行处理。可以将这个过程形象的想象成所有的声明(变量和函数)都会被“移动到”各自作用域的最顶端,这个过程被称为提升。
声明本身会被提升,而包括函数表达式的赋值在内的赋值操作并不会提升。
要注意避免重复声明,特别是当普通的var声明和函数声明混在一起的时候,否则会引起很多危险的问题!