首页 > 代码库 > JS中的声明提升问题
JS中的声明提升问题
我们习惯将 var a = 2; 看作一个声明,而实际上JavaScript引擎并不这么认为。他将 var a 和 a = 2 当作两个单独的声明,第一个是编译阶段的任务,第二个则是执行阶段的任务。
——《你不知道的Js》
变量提升
变量提升的概念已经为大家所熟知,简单来讲就是在代码执行前编译器会将变量的声明提升至其所在作用域(不是全局作用域)的顶端。但在这过程中还有一些细节需要注意。比如赋值与声明提升的先后关系。先看一个例子。
由于存在变量声明提升,对 a 的声明已经提升至最前,这里打印变量a的值就不会抛出ReferenceError( a is not defined )异常。但是奇怪的是 a 的值为 undefined 这就说明了变量的赋值操作并未随着变量声明的提升而被提升,而是仍被留在原地。就等同于下图的样子。
函数声明提升
跟变量声明的提升一样,只不过声明的不再是变量而是一个函数了。就像这样 var a = > function a(){...} 。还是来看例子。
由于存在函数声明提升,函数 foo 被正常执行打印出 a 的值为2。但这里同样有一个细节需要注意。
这里看到,函数声明会被提升,但函数表达式并不会。其中的道理跟上面的变量赋值是一样的。对变量 foo 的声明首先被提升,将一个匿名函数赋值给变量 foo 的操作还被丢在原地。像下面这样。
执行到foo()时,这里的foo只是一个值为 undefined 的小变量,还未被改变为函数呢。对一个 undefined 进行函数调用当然要抛出 TypeError 错误。
说到这里,还有一种具名的函数表达式(非匿名函数表达式),常常被人(我)误解。看例子。
为什么会出现 ReferenceError ? 先从函数的声明方式说起。函数有且只有两种声明方式。
- 一般函数声明:function foo(){ }
- 函数表达式声明:var foo = function(){ }; 等号后面必须为匿名函数
对于 var foo = function bar(){ }; 这种具名函数表达式声明函数的方式等同于普通函数表达式。但此时的 bar 仅仅作为foo()的一个内部属性,这也就是上例中抛出 ReferenceError 的原因。
JS中的声明提升问题