JavaScript运行三部曲
Step1:语法分析
Step2:预编译
Step3:解释执行
今天着重介绍一下预编译的过程,在开始正式介绍预编译之前,还要补充两个小知识:
一个是:暗示全局变量 imply global
这个是说 任何变量,如果未经声明就赋值次变量就归全局所有
a =123; // 这是一个未经声明就赋值的变量;
console.log(a);
我们执行这个代码块的时候,发现不会报错,并且a 可以正常访问~
通过window访问也可以找到a
再来看这样一个函数
function test(){
var a = b = 123 ;
}
test();
在全局上b是可以找到的,因为b是未经声明就赋值的变量
第二个小知识是: 一切声明的全局变量,全是window的属性
换一种方式理解可以认为 window就是全局的域,我们在定义一个全局变量的时候 ,会存放在window中,当我们需要用到这个变量的时候会到window中寻找
//现在我要定义一个全局变量
var a = 123;
//此时,JavaScript为我们开辟了一个空间叫:window
/*
window{
a :123;
}
↑就像这样一个空间,存放了我们的变量,需要用的时候从这里来拿
*/
补充完之后,正式进入预编译的环节,我们经常可以听到一句关于预编译的话:【变量 声明提升, 函数声明 整体提升】,其实这句话只是涵盖了预编译的一部分而已
其实,纵观整个预编译过程(发生在函数执行前一刻),总共要分四个步骤
- 创建AO对象
- 寻找形参和变量声明,把形参和变量声明作为AO对象的属性名,同时赋值为undefined
- 将实参值和形参值相互统一起来
- 在函数体里找函数声明(并非函数表达式)作为属性名(当然已经存在的就不用再次作为属性名啦) ,并把这个函数体整体赋给它。
举个小栗子:
function fn(a){
console.log(a);
var a = 123;
console.log(a);
function a(){}
console.log(a);
var b = function(){}
console.log(b);
function d(){}
}
fn(1);
//请问打印结果是啥?
//解题思路
//首先:创建AO对象 Activation Object (执行期上下文)
AO{
//第二步:找形参和变量声明
a:undefined;
b:undefined;
}
//第三步: 将实参和形参统一
//此时AO变为如下形式
AO{
a:1;
b:undefined;
}
//第四步:找函数声明
//此时AO变为如下形式
AO{
a: function a (){};
b: undefined;
d: function d() {};
}
//至此,AO对象创建完毕~~
//现在轮到我们来看每一条的输出是什么
此时万事俱备,开始执行,首先运行到第一条输出
此时我们在AO中查看,此时应该打印 function a(){};
运行到第二条语句:var a = 123;
此时AO发生变化
AO{
a: 123;
b: undefined;
d: function d() {};
}
运行到第三条语句:
在AO中查看 发现 a:123
所以打印 123;
运行到第四条语句:function a(){} 这条语句在预编译的过程中已经被提升上去了,所以不用管啦!
运行到第五条语句:要求我们打印a
此时AO中的 a 依旧为123;
所以打印 123;
运行到第六条语句:var b = function(){}
此时AO发生变化
AO{
a: 123;
b: function(){};
d: function d() {};
}
运行到第七条语句,要求我们打印b
此时AO中 b 为function(){}
所以打印 function(){}
至此,最终答案为:
function a(){};
123;
123;
function(){}
运行结果如下:
小伙伴们,你们做对了吗?