深入理解JavaScript的声明提升

时间:2022-12-20 15:43:07

js中的变量声明提升

我们先来看一段代码

console.log(a)  //undefined
var a = 1

上面这两行代码不难理解, var定义的变量声明都会被提升至本作用域的顶部。所以上面的两行代码等价于下面的三行代码。

var a
console.log(a)
a = 1

再来看

console.log(a)  //报错
a = 1

前面已经说过,只有var定义的变量声明才会被提升。
我们继续

var a = 1
function test() {
    console.log(a)  //undefined
    var a = 2
    console.log(a)  //2
}
test()

在函数test中有var a = 2,所以存在变量声明提升至本作用域的顶部,而var a = 2的作用域是test函数,所以输出的为undefined,2而不是1,2。

js中的函数声明提升

同样,我们还是先看一段代码

console.log(a)  //function a()
function a() {}

从上面示例中,我们可以知道在js中也存在函数声明提升,而且是函数声明整体都会提升至本作用域顶部(最先被编译),为什么说的是存在函数声明提升呢,我们接着往下看

console.log(a)  //undefined
var a = function () {}

我们会发现,当我们使用函数表达式定义一个函数时,会存在变量提升但是不会进行函数声明提升。当然我们定义一个函数不光只有函数声明与函数表达式两种方式,让我们再来看看构造函数定义函数时是否存在函数声明提升。

console.log(a)  //undefined
var a = new Function()

不难发现,使用构造函数定义的函数会存在变量提升但是不会进行函数声明提升。
是不是感觉豁然开朗了呢,先别着急,我们在看一下下面这段代码,或许你会有什么意外的发现

console.log(a())
function a() {return 1}  //函数1
console.log(a())
var a = function () {return 2}  //函数2
console.log(a())
var a = new Function('return 3') //函数3 console.log(a()) function a() {return 4}  //函数4
console.log(a())
var a = function () {return 5}  //函数5
console.log(a())
var a = new Function('return 6') //函数6 console.log(a())

答案是4、4、2、3、3、5、6,如果你的答案和正确答案有出入的话,说明你可能并没有真正理解函数声明提升,下面我们从这个题目出发具体讲解一下函数声明提升(答案正确的童鞋可以跳过啦)。
在浏览器解析这段代码之前,会先进行函数声明提升,即函数1与函数4会被提升至本作用域最顶部,而函数1与函数4同名,所以函数4会覆盖函数1。而函数2、3、5、6则是变量提升,只有在代码被执行的时候才会将函数赋予声明的变量,所以输出的结果是4、4、2、3、3、5、6。不过可能有的同学会有疑问,用构造函数创建的a也会进行声明提升,为什么第一个输出为4而不是报错或者undefined。其实道理很简单,函数6与函数4的关系如下

function a() {return 4} //函数4提升至作用域最顶部
var a       //函数6对应的变量a提升至作用域顶部,重新声明不会改变原先的函数a
console.log(a)
//function a() {return 4} //函数4,此语句已被提升至最顶部
var a = new Function('return 6')  //函数6

总结:var定义的变量声明会被提升至本作用域的顶部,而函数声明整体都会被提升至本作用于顶部,且函数声明提升的优先级高于var定义的变量声明提升的优先级。