在JavaScript中存在一种预编译的机制,这也是Java等一些语言中没有的特性,也就正是因为这个预编译的机制,导致了js中变量提升的一些问题,下面这两句话能解决开发当中一部份问题,但不能解决所有问题,还有一些问题是你必须通过学习预编译才能解决的。
预编译什么时候发生
局部预编译是在函数执行的前一刻。
全局预编译是页面加载完成是执行。
js运行的三部曲
1.语法分析
2.预编译
1.解释执行
AO局部预编译4个步骤
1.创建AO对象(Activation Object)执行期上下文
2.找形参和变量声明,将变量和形参作为Ao的属性名,值为undefined
3.将实参值和形参统一。
在函数体里面找函数声明,值赋予函数体
GO全局预编译3个步骤
1.创建GO对象(Global Object)全局对象。
2.找变量声明,将变量名作为Go属性名,值为undefined;
查找函数声明,作为GO属性,值赋予函数体。
由于全局变量中没有参数的概念,所以省去了实参与形参统一这一步。
巩固基础练习
关于AO对象的例子
// 函数
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);
1.预编译的第一步:创建AO对象
AO{
}
2.预编译第2步:找形参和变量声明,将形参名和变量名作为AO对象的属性名
AO{
a : undefined,
b : undefined
}
3.预编译第3步:将实参值和形参统一
AO{
a : 1,
b : function(){…}
}
4.预编译第4步:在函数体里面找函数声明,值赋予函数体。
AO{
a : function a(){…},
b : undefined,
d : function d(){…}
}
结果
1.fun()
2.123
3.123
4.fun()
!函数执行完毕销毁AO对象
关于GO对象的例子
global = 100;
function test(){
console.log(global);
var global = 200;
console.log(global);
var global = 300;
}
test();
var global;
1.全局预编译第1步:创建GO对象
GO{
}
2.全局预编译第2步:找变量声明,将变量名作为GO属性名,值为undefined
GO{
global:undefined
}
3.全局预编译第3步:查找函数声明,作为GO属性,值赋予函数体
GO{
global:undefined
}
4.局部预编译第1步:创建AO对象
AO{
}
5.局部预编译第2步:找形参和变量声明,将形参名和变量名作为AO对象的属性名
AO{
global: undefined
}
6.局部预编译第3步:将实参值和形参统一(此函数没有形参)
AO{
global: undefined
}
7.局部预编译第4步:在函数体里面找函数声明,值赋予函数体。(此函数内没有函数声明)
AO{
global: undefined
}
提升题
global = 100
function fn(){
console.log(global);
global = 200;
console.log(global);
var global = 300;
}
fn()
var global
//AO中有自己的变量global,不调用GO的global。(就近原则)