预编译
JS属于解释型语言,在执行过程中顺序执行,但是会分块先预先编译然后才执行。
理解预编译前需要清楚两个概念
函数声明(整体提升) 变量赋值(声明提升)
变量赋值(声明提升)
正常来说js会经历三个过程
1. 语言分析 ---------> 检查是否有语法错误 和低级错误
2. 预编译 ---------> 分情况
全局变量: 创建 GO对象
局部对象: 创建 AO对象
提升当前作用域下 var声明的变量 赋值undefined
提升当前作用域下 所有声明的函数并赋值function
3. 解析执行 --------->
对每一行代码解析执行
对提升的变量重新赋值
<script>
console.log(a)
var num = 10;
console.log(num)
var a = 20
foo()
function foo(){
console.log(acc)
var acc = 20
console.log(acc)
}
</script>
此时在<script> 标签开始的位置
会生成一个对象 名称叫做GO (当然,开发者是看不见的)
首先搜索全局里面是否含有var
如果有var 将变量全部提升且赋值为undefined
GO = {
num:undefined
a:undefined
}
初始化所有的变量为undefined之后
开始逐行解析执行 注意!!这里仅仅是变量名替身 值并未提升
第一行console.log(a)
此时的a还未提升变量值 值为unedfined
由于console.log()默认向上查找变量的最近的一次赋值
所以输出undefined
当执行到第二行的时候
GO{
num:10;
a:undefined
}
在这个时候 变量的值才会去提升
console.log(num) 查找到最近的一次GO对象里面的num为 10
接下来看AO创建 当浏览器解析执行到
function foo() {
的时候 浏览器会基于GO对象创建一个AO对象
具体流程和GO一样 只不过这里会涉及到作用域
此时的AO对象 回和GO一样查找函数体内的变量
AO{
acc:undefined
}
然后逐行解析执行
console.log(acc);
这里由于变量值还未提升 所以输出undefined
当解析到 var acc = 20的时候
此时
AO{
acc:20
}
此时运行到第四行 查找相关的AO对象内的acc
输出20
console.log(acc);
//注意 此时的函数体已经执行完毕 此时AO对象将会自行销毁
所以函数体外部作用域无法访问函数体内部的变量