目录
预编译
js的执行顺序
- 语法分析
- 解释执行
预编译什么时候发生
- 预编译分为全局预编译和局部预编译
- 全局预编译发生在页面加载完成时执行
- 局部预编译发生在函数执行的前一刻
预编译步骤
- AO(Activation Object) 活动对象,也叫执行期上下文,作用域。这里指的时函数的局部作用域
- GO(Global Object) 全局对象,与window对象相同
- GO时全局预编译,会优先于AO创建执行
局部预编译步骤
- 创建AO(Activation Object)对象
- 寻找形参和变量声明,变量和形参作为AO对象的属性名,赋值为undefined
- 实参赋值给形参
- 找函数声明、赋值
- 执行
全局预编译步骤
- 创建GO对象(Global Object)全局对象。
- 找变量声明,将变量名作为GO属性名,值为undefined
- 查找函数声明,作为GO属性,值赋予函数体
例子
例1
function test(a){
console.log(a);
var a = 1;
console.log(a);
function a(){}
console.log(a);
var b =function (){};
console.log(b);
function d(){};
}
test(2);
打印结果:
ƒ a(){}
1
1
ƒ (){}
创建AO
AO={}
找变量声明
AO={
a:undefined,
b:undefined,
}
实参赋值
AO={
a:2,
b:undefined
}
寻找函数声明
AO={
a:function a(){},
b:undefined
d:function d(){}
}
执行函数
AO={
a:function a(){}->1,
b:undefined->function(){},
d:function d(){}
}
例2
function test(a,b){
console.log(a);
c=0;
var c;
a=5;
b=6;
console.log(b)
function b(){};
function d(){};
console.log(b);
}
teset(1)
打印结果:
1
6
6
创建AO
AO={}
找变量声明
AO={
a:undefined,
b:undefined,
c:undefined,
}
实参赋值
AO={
a:1,
b:undefined,
c:undefined,
}
寻找函数声明
AO={
a:1,
b:function b(){},
d:function d(){},
c:undefined,
}
执行函数
AO={
a:5,
b:6,
d:function d(){},
c:0,
}
例3
var a =1;
function a(){
console.log(2);
}
console.log(a);
创建GO
GO={}
寻找变量声明
GO={
a:undefined
}
找函数声明
GO={
a:undefined
}
执行
GO={
a:1,
}
例4
console.log(a,b);
function a(){
console.log(2);
}
var b =function(){};
ƒ a(){
console.log(2);
}
undefined
创建GO
GO={}
寻找变量声明
GO={
a:undefined,
b:undefined
}
找函数声明
GO={
a:function(){},
b:undefined
}
执行
GO={
a:function(){},
b:undefined
}
例5
var b = 3;
console.log(a);
function a(a){
console.log(a);
var a =2;
console.log(a);
function a(){};
var b=5;
console.log(b);
}
a(1);
打印结果:
ƒ a(){}
2
5
创建GO
GO={}
寻找变量声明
GO={
a:undefined,
b:undefined
}
找函数声明
GO={
a:function(){},
b:undefined
}
执行
GO={
a:function(){},
b:3
}
创建AO
AO={}
找变量声明
AO={
a:undefined,
b:undefined,
}
实参赋值
AO={
a:1,
b:undefined,
}
寻找函数声明
AO={
a:function a(){},
b:undefined,
}
执行函数
AO={
a:2,
b:5,
}
作用域&作用域链
- 每个对象都有一个[[scope]]
- 函数创建时,生成的一个个js内部的隐式属性
- 函数存储作用域的容器叫做作用域链
- AO 函数的执行期上下文
- GO 全局的执行期上下文
- 函数执行完成后,AO是要销毁的。每次执行都会产生一个新的AO
- 全局上下文GO在应用程序推出前才会被销毁。(关闭网页,推出浏览器)
- 当代码执行到函数时,函数的上下文被推到一个上下文栈中。该函数执行完毕,上下文栈会弹出该上下文,将控制权返还给之前的执行上下文
function a(){
function b(){
var b = 2;
}
var a = 1;
b();
}
var c = 3;
a();
当a函数定义&执行前
当b函数定义&执行前
当a函数&b函数执行结束
为什么外部访问不到内部的变量?
- 查找变量的时候,会从作用域链的顶端开始查询
- 外部执行期上下文不包含内部的执行器上下文
闭包
当内部函数被返回到外部并保存的时候,就一定会产生闭包
- 闭包会产生原来的作用域链不释放
- 过度的闭包可能会导致内存泄漏或加载过慢
function test1(){
function test2(){
var a = 2;
console.log(a);
}
var a = 1;
return test2;
}
var c = 3;
var test3 = test1();
test3();