JS预编译过程
JavaScript 在编译的过程中都
做了什么?
- 语法分析
- 预编译
- 解释执行
主要介绍的是
预编译都做了什么?这个知识点 学习 我是在渡一成哥的JavaScript课程中学习的 , 如果有兴趣可以去看看
在 js 执行预编译的过程中 , 大致发生了这三个步骤
- 变量声明整体提升
- 形参和实参统一
- 函数声明整体提升
先看几个简单的例子
function temp(){
console.log(a)
}
temp()
//会报错 , a is not defined
function temp(){
console.log(a)
var a
}
temp()
//打印: undefined
temp()
function temp(){
console.log(a)
var a
}
//打印: undefined
视觉 上会报错的代码, 并没有出现报错提示, 依然能够正常执行
都是因为 预编译 的原因
局部预编译过程
注意:var a = 10这是一个
变量声明+变量赋值的过程, 可以拆分为var a; a = 10
用一段代码来作为演示
function temp(a,b){
//打印a的结果
console.log(a)
//声明一个函数a
function a(){}
//给a进行赋值
a=10
//打印a的结果
console.log(a)
//声明一个函数b
function b(){}
//打印b的结果
console.log(b)
}
//调用temp()这个函数
temp(10,5)
这段代码的执行结果为:
ƒ a(){} //第3行打印结果 10 //第9行打印结果 ƒ b(){} //第13行打印结果
为什么会有这样的结果? 我来给大家解析一下这段代码的执行
AO 对象: Activation Object(执行期上下文,作用是理解的作用域,函数产生的执行空间库)
变量声明整体提升
当函数开始执行的时候, 在浏览器内部会生成一个 AO 对象
就开始执行我们的预编译第一步 , 变量声明整体提升 , 会把我们在函数内声明的变量都给取出来放在AO 对象中
并给他们赋值 , 默认初始值为 undefined
//a和b是形参,在定义函数时,声明的参数变量仅在函数内部可见
AO{
a:undefined,
b:undefined
}
形参和实参统一
预编译的第二步, 形参和实参统一
如果函数中存在 实参和形参 的数据传递, 则会有这一步, 如果不存在, 则不会有这一步
temp(10,5)
传递过来的值 , 给 AO 对象 中的变量赋值
AO{
a:10,
b:5
}
函数声明整体提升
预编译的第三步, 函数声明整体提升
我们声明了 函数a和函数b , 再次改变了 AO 对象
//在我们的temp函数中, 我们声明了a函数和b函数
AO{
a:fn(){},
b:fn(){}
}
逐行解释代码
当预编译的前三步执行完后 , 就会开始逐行解释执行代码
这是预编译前三步执行后的
AO 对象
AO{
a:fn(){},
b:fn(){}
}
function temp(a,b){
//打印结果: fn(){}
console.log(a)
//因为函数已经声明过了,会直接跳过这行
function a(){}
//赋值操作,再次改变AO对象
//AO{ a:10, b:fn(){} }
a=10
//打印结果:10
console.log(a)
//因为函数已经声明过了,会直接跳过这行
function b(){}
//打印结果为:fn(){}
console.log(b)
}
什么时候开始局部预编译
预编译发生在
函数执行的前一刻
- 变量声明整体提升
- 形参和实参统一
- 函数声明整体提升
- 逐行解释代码
全局预编译过程
全局预编译, 你需要先学习局部预编译
全局预编译与局部预编译不同, 全局预编译发生在页面加载完成时
GO 对象: Global Object(window 就是 GO)//GO === window, GO 和 window 是一个东西 //这三条语句在全局中是一样的 console.log(a); console.log(window.a); console.log(go.a);
在全局预编译中, 会成功一个GO 对象 , 并且也会发生局部预编译的步骤
- 变量声明整体提升
- 形参和实参统一
- 函数声明整体提升
用一段代码演示
a = 10;
var a;
temp()
function temp(){
console.log(a)
}
执行结果为: 10
变量声明整体提升
当页面加载完成时, 在浏览器内部会生成一个 GO 对象
就开始执行我们的预编译第一步 , 变量声明整体提升 , 会把我们在函数内声明的变量都给取出来放在AO 对象中
并给他们赋值 , 默认初始值为 undefined
GO{
a:undefined
}
形参和实参统一
此处代码并没有形参和实参,所以并没有这一步
函数声明整体提升
预编译的第三步, 函数声明整体提升
我们声明了 temp函数, 再次改变了 GO 对象
GO{
a:undefined,
temp:fn(){}
}
逐行解释代码
当预编译的前三步执行完后 , 就会开始逐行解释执行代码
这是预编译前三步执行后的
GO 对象
GO{
a:undefined,
temp:fn(){}
}
//对a进行赋值操作,改变了GO对象,GO{ a:10, temp:fn(){} }
a = 10;
//已经进行过变量声明提升,跳过该行
var a;
//当到这一步的时候,执行函数,就会在此处生成一个局部的AO对象
temp()
function temp(){
console.log(a)
}
temp( )的执行生成了一个AO对象
AO{}
//但是AO对象中什么都没有,所以会直接执行语句
console.log(a)
//AO对象中并没有发现a,就会往上找,找上一层的作用域,直到找到第一层的GO对象中
//我们知道此时的GO:{ a:10, temp:fn(){} }
打印结果为: 10
知识点
-
任何全局变量都是 window 上的属性
-
没有声明就赋值的变量,归 window 所有,就是在 GO 里面预编译
function test(){ var a = b =123; console.log(window.b); } test(); //打印结果为123 //b未进行定义,所以b会直接在GO中预编译,b是属于全局的属性 function temp(){ a = 10 } temp() function abc(){ console.log(a) } abc() //a未进行定义,所以a会直接在GO中预编译,a是属于全局的属性,所以在abc中也可以访问 //打印结果为10