# 预编译
# 语法分析
语法分析很简单,就是引擎检查你的代码有没有什么低级的语法错误
# 预编译
预编译发生在代码执行的前一刻,预编译简单理解就是在内存中开辟一些空间,存放一些变量与函数 ;
# 解析执行
解释执行顾名思义便是执行代码了
# 预编译前奏
暗示全局变量 imply global
任何变量,如果变量未经申明就赋值,此变量就为 全局对象 所有。
a = 1;
console.log(window.a);
function test() {
var a = b = 2;
}
test();
console.log(window.b);
# 全局变量
一切申明的 全局变量, 全是 window 的属性, window 就是全局的域
# GO 和 AO
JS 在执行前会产生一个 GO ,也就是我们说的全局作用域 。 当一个方法被调用时会形成一个局部作用域 AO
全局代码在执行的时候,先是 变量提升 , 在全局作用域内添加 属性,然后是 函数(以函数声明创建的函数)提升,再是代码执行
我们先来个简单的小🌰来看看:
console.log(b);
var b = 2;
此时我们打印出来 b 的值为 undefined,那我们不定义 b 直接 打印 b 是什么情况呢
console.log(b);
浏览器报错. b is not defined
为什么在 console.log 后和不定义 b 会有如此大的差别,这就是预编译起到的作用
我们再看看下面这个列子
console.log(a);
var a = 123;
function a() {
}
console.log(a);
打印结果
ƒ a() {
}
123
结果怎么来的呢???
那我们就得看下面的 预编译 四部曲
# 预编译四部曲
创建 GO/AO 对象
找形参和变量申明,将变量和形参名作为 AO 属性名,值为 undefined
将实参值和形参值统一
在函数体里面找函数申明,值赋予 函数体
这四部是什么意思呢,我们举个例子看看:
function fn(a) {
console.log(a);
var a = 123;
console.log(a);
function a() { }
console.log(a);
console.log(b);
var b = function () { }
console.log(b);
}
fn(1);
大家觉得应该输出什么呢?
我们来分析下:
首先方法调用形成一个局部 *AO
AO{
}
找方法里面的形参和变量申明, fn 里面 只有 a 和 b,作为 AO 的属性并把值设置为 undefined
AO{
a:undefined,
b:undefined
}
然后将形参和实参的值统一,什么意思呢,就是给 形参 a 赋值为 实参 1,此时的 AO:
AO{
a:1,
b:undefined
}
最后一步函数体找函数申明,并赋值为函数体, 我们找到了 函数申明 function a() { } ,有人会问 b呢,不好意思 b 是 函数表达式,因此忽略,此时 AO 为:
AO{
a:function a() { },
b:undefined
}
到此 函数预编译完成,下面开始执行:
第一次 console.log(a) 打印即为 AO 里面的 a => function a() { }
第二次 console.log(a) 执行 a 的赋值,此时 a =>123
第三次 console.log(a) 函数function a() { } 已经预编译申明过, 因此直接忽略, a 还是为 123
第一次 console.log(b) 打印即为 AO 里面的 b => undefined
第二次 console.log(b) 执行 b 的赋值,此时 b =>function () { }
我们来看看打印的是否如我们分析的这样:
ƒ a() { }
123
123
undefined
ƒ () { }
undefined
看来没有问题。😄
好了,我们已经知道了 预编译的过程,那让我们再来一题看看:
function test() {
console.log(b);
if (a) {
var b = 100;
}
c = 234;
console.log(b);
console.log(c);
}
var a;
test();
a = 10;
console.log(a);
console.log(c);
一样的,我们首先生成 GO,AO
GO{
a:undefined
}
AO{
b:undefined
}
第一次打印 b 的值 为 undefined 没问题,
此时 AO 中没有a 属性,往上找全局属性 GO ,ok a 为 undefined,条件不成立 b 还是 undefined
打印 c 没什么好说的,直接就是 234
函数 test() 执行完毕 下面 a 进行赋值, 因此 打印 a 为 10
打印 c 相当于 访问 window.c 因此还是 234
# 小练习
a = 100;
function deme(e) {
function a() { }
arguments[0] = 2;
console.log(e);
if (a) {
var b = 123;
var c = function () { }
}
var c;
a = 10;
var a;
console.log(b);
f = 123;
console.log(c);
console.log(a);
}
var a;
deme(1);
console.log(a);
console.log(f);
# 总结
未经申明就赋值,此变量就是全局变量所有,一切申明的全局变量,全是 window 属性
预编译发生在 变量申明 和 函数申明, 匿名函数 和 函数表达式 不参与预编译
变量声明提升:无论变量调用和声明的位置是前是后,系统总会把声明移到调用前,注意仅仅只是声明,所以值是 undefined
函数声明整体提升:无论函数调用和声明的位置是前是后,系统总会把函数声明移到调用前面.如果函数名同形参或变量名同名,则会赋值为 函数体
只有在解析执行才会对变量初始化