表现形式
无论在函数的何处声明的变量,都会被提升至函数的开头部分,可以在变量声明前访问但不会报错。
为什么这样?
造成变量提升的本质原因是因为JavaScript引擎在代码执行前回一个解析的过程,创建执行的上下文,初始化一些代码在执行时所需要使用的对象。在访问一个变量时,会在当前的执行上下文中的作用域中去查找,然而作用域的首端指向的是当前执行的上下文中的变量,这个变量是当前执行上下文的一个属性,这个变量包含了函数的形参,所有的函数和变量的声明,这个变量就会在代码解析的时候进行创建。
在解析阶段:
JavaScript会检查语法,对函数进行预编译。创建全局执行上下文->将即将要执行的变量,函数声明都拿出来且赋值为undefined。
在函数执行之前,仍会创建一个类似全局的执行上下文一样的函数执行上下文,在此时,函数将会多出this,arguments,函数的参数。
全局上下文
定义变量,函数声明
函数上下文
定义变量,函数声明,this,arguments
在执行阶段
按照代码的顺序进行一次执行
那么为什么会有变量提升?
1 : 提高性能
因为在代码执行会进行一次代码检查和预编译(只进行一次),这样就不需要在函数变量每次执行的时候都再进行一次代码检查和重新解析,
2: 容错了提升
a=2;var a;console.loga) //2
例如这样的一段代码,正是因为变量的提示在执行时就不会进行报错。
结尾
虽然变量提升带来了一定的有点,但同时也会造成一些其他的问题。类似于
var useString = 'xiaokonglong';
for var i = 0; i < useString.length; i++) {
console.loguseString[i]);
}
console.logi); // 12
正是因为变量的提升,导致i变成了全局变量,在结束后并不会销毁,所以会打印出来useString.length-1
。
在ES6中 let | const 将会解决这个问题,同样的代码,使用let / const时结果就会不一致
var useString = 'xiaokonglong';
for let i = 0; i < useString.length; i++) {
console.loguseString[i]);
}
console.logi); // i is not defined