js:变量提升

135 阅读2分钟

无论作用域中的声明在什么地方出现,都将在代码本身被执行前首先处理。可以将这个过程形象的想象成所有声明都会被移动到各自的作用域最顶端,这个过程被称为提升。 举两个栗子

猜猜下面代码打印输出的是什嘛?

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

引擎在解释JavaScript代码之前首先对其进行编译,就是包括变量个函数在内的所有声明都会在任何代码被执行之前先处理。

当你看到var a=1的时候,可能会认为这是一个声明,但实际上会将其看成var a,和a=1。var a是在编译阶段、a=1赋值声明是在执行阶段。

所以第一个的输出结果是1,第二个的输出结果第undefined。

在举个栗子:

console.log(a)
var a=10
function foo(){
console.log(a)
var a=20
console.log(a)
}
foo()
console.log(a)

输出结果: undefined、undefined、20、10

函数声明会被提升但是函数表达式不会被提升。

foo()  // typeError 不是REfernceError
var foo=function f1(){

}

函数会首先被提升,然后才是变量。

foo()
var foo
function foo(){
console.log(1)
}
foo=function(){
console.log(2)
}

会输出1而不是2.

这个代码片段会被引擎理解为这样,var foo尽管出现在function foo()...的声明之前,但他是重复的声明,被忽略掉了。

function foo(){
console.log(1)
}
foo()
foo=function(){
console.log(2)
}

ES6中新增了let和const关键字,let和const让JavaScript有了“块”级作用域,并且使用let和const 声明的变量和函数是不会被提升现象的。

var/function/function声明和let/const声明的区别在于初始化。 前者在作用域的顶部创建绑定时用undefined或(generator)函数初始化。 然而,词法声明的变量保持未初始化。 这意味着当您试图访问它时,会抛出一个ReferenceError异常。 只有当let/const/语句被求值时,它才会被初始化。