执行上下文
执行一个函数所做的准备工作,这个准备工作就是执行上下文
执行上下文的生命周期
- 创建阶段
在这个阶段,执行上下文会分别创建变量对象,建立作用域链,以及确定this的指向
- 代码执行阶段
创建完成后,就会开始执行代码,这个时候,会完成变量赋值,函数引用以及执行其他代码
- 回收阶段
执行上下文出栈等待虚拟机回收执行上下文
变量对象
定义 : 变量对象是与执行上下文相关的数据作用域,存储了在上下文中定义的变量和函数声明
变量对象只是规范上的或者说引擎上实现的,不可在JavaScript环境中访问.
- 全局上下文中的变量对象就是全局对象
- 函数上下文中的变量对象初始化只包括Arguments对象。在进入上下文时被激活变成活动对象(activation object , AO)。AO包括VO、arguments以及形参、函数声明等属性值(Arguments是一个类数组,包含了函数的实际参数)
执行上下文创建阶段
变量对象包括 :
- 1.函数的所有形参(如果是函数上下文)
- 由名称和属性值组成的一个变量对象的属性被创建
- 没有实参,属性值设为undefined - 2.函数声明
- 创建一个变量对象,变量名=变量值(函数对象(function-object))
- 如果变量对象属性名已存在,则完全替换替换这个变量对象的属性值 - 3.变量声明
- 创建一个变量对象,变量名=变量值(undefined)
- 如果变量名称和已经声明的形式参数或函数相同,则变量声明不会影响已经存在的这类属性
举例说明:
function foo(a) {
var b = 2;
function c() {}
var d = function() {};
b = 3;
}
foo(1);
//执行上下文创建阶段的AO
//var b=2 理解成var b; b=2
AO = {
arguments: {
0: 1,
length: 1
},
a: 1,
b: undefined,
c: reference to function c(){},
d: undefined
}
//代码执行阶段的AO
AO = {
arguments: {
0: 1,
length: 1
},
a: 1,
b: 3,
c: reference to function c(){},
d: reference to FunctionExpression "d"
}
例2 :
console.log(foo); //ƒ foo(){ console.log("foo");}
var foo = 1;
function foo(){
console.log("foo");
}
console.log(foo)//1
//在进入执行上下文时,会先处理函数声明,再处理变量声明,如果如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性。
//在代码执行阶段,执行foo=1
确定this的指向
this只有在执行时才能确定它的指向,因为它是执行上下文的一部分.
this指向调用它的上一级对象
call()、apply() 、bind()可以修改this的指向,另外箭头函数没有自己的this
执行上下文栈
用来管理执行上下文
function fun3() {
console.log('fun3')
}
function fun2() {
fun3();
}
function fun1() {
fun2();
}
fun1();
当执行一个函数时就会创建一个执行上下文,并且压入执行上下文栈,当函数执行完毕后,就会将函数的执行上下文从栈中弹出
对上面代码的处理
// 伪代码
ECStack = [];//执行上下文栈
ECStack.push(<fun1> functionContext);
ECStack.push(<fun2> functionContext);
ECStack.push(<fun3> functionContext);
ECStack.pop();// fun3执行完毕
ECStack.pop();
ECStack.pop();