1.预解析
JavaScript 中代码的执行是由浏览器中 JavaScript 解析器来执行的。JavaScript 解析器执行 JavaScript 代码的时候,分为两个过程:预解析过程和代码执行过程。
预解析过程
- 把变量的声明提升到当前作用域的最前面,只会提升声明,不会提升赋值
- 把函数的声明提升到当前作用域的最前面,只会提升声明,不会提升调用
- 先提升 函数声明,再提升变量声明
2.变量提升
定义变量时,变量的声明会被提升到作用域的最上面,变量的赋值不会提升
<script>
console.log(a)//undefined
var a = 10
num = 6
console.log(num, '2')//6
var num
</script>
以上代码编译后的代码结构可以看做如下运行顺序
<script>
var a
console.log(a)//undefined
a = 10
var num
num = 6
console.log(num, '2')//6
</script>
3.函数提升
- JavaScript 解析器首先会把当前作用域的函数声明提前到整个作用域的最前面
- 函数提升只会提升函数声明式写法,函数表达式的写法不存在函数提升
- 函数提升的优先级大于变量提升的优先级,即函数提升在变量提升之上
<script>
fn1()
fn2()
function fn1() {
console.log('fn1')//fn1
}
var fn2 = function () {
console.log('fn2')//Uncaught TypeError: fn2 is not a function
}
</script>
以上代码编译后的代码结构可以看做如下运行顺序
<script>
function fn1() {
console.log('fn1')//fn1
}
fn1()
fn2()
var fn2 = function () {
console.log('fn2')//Uncaught TypeError: fn2 is not a function
}
</script>
4.变量提升与函数提升综合示例
<script>
var a = 1
function fn() {
a = 10
console.log(a)//10
return
function a() {
}
}
fn()
console.log(a)//1
</script>
以上代码编译后的代码结构可以看做如下运行顺序
<script>
var a = 1
function fn() {
var a = function () { }
a = 10
console.log(a)//10
return
}
fn()
console.log(a)//1
</script>
注意:ES6 新增了 let 和 const 关键字,使得 js 也有了块级作用域,而且使用 let 和 const 声明的变量和函数式不存在提升现象的。呃呃呃,是不是学了个寂寞~