1.0.0 函数的执行环境(执行上下文)
每个函数的执行,都会创建一个与该函数相关的函数执行环境,又称函数执行上下文(内部对象,可理解为作用域)。
1.1.0 产生执行上下文的两个阶段
1.1.0.1 创建阶段
当函数被调用,但未执行任何内部代码之前;
- 创建作用域链(Scope Chain);
- 生成变量对象(函数的形参、函数声明、变量声明);
- this的指向;
1.1.0.2 代码执行阶段
- 创建状态负责处理定义属性的名字,不为其指派具体的值,以及形参/实参的处理;
- 一旦创建阶段完成,执行流进入函数并且激活/代码执行阶段,Execution Context object就会更新。
1.1.0.3 执行完毕(垃圾回收机制)
函数执行完毕,等待被回收
1.2.0 变量对象
基本概念:
- 变量对象(varibale object)是与执行上下文相关的数据作用域;
- VO是与上下文关联的特殊对象,用于存储被定义在上下文的变量和函数声明;
- VO是一个抽象的概念,不同的执行上下文中,它表示不同的Object。例如在global全局上下文中,变量对象也是全局对象自身[global object](即:我们可以通过全局对象的属性来指向全局变量);
变量对象的创建:
- 建立arguments对象。检查当前上下文中的参数,建立该对象下的属性和属性值;
- 检查当前上下文的函数声明,即通过function关键字声明的函数。在变量对象中以函数名建立一个属性,属性值为指向该函数所在的内存地址的引用;如果函数名的属性已经存在,那么该属性将会被新的引用所覆盖;
- 检查当前上下文中的变量声明,每找到一个变量声明,就会在变量对象中以变量名建立一个属性,属性值为undefined。如果该变量名的属性已经存在,为了防止同名的函数被修改为undefined,则会直接跳过,原属性值不会被修改;
function test () {
console.log(a);
console.log(foo());
var a = 1;
function foo () {
return 2;
}
}
test();上述test运行时的执行上下文创建过程如下:
testEC = {
// 变量对象
VO: {},
scopeChain: {},
this
}
VO = {
arguments: {...}, // 注:再浏览器的展示中,函数的参数可能并不是放在arguments对象中
foo: <foo reference>, // 表示foo的地址引用
a: undefined
}注意:代码未进入执行阶段之前,变量对象中的属性都不能访问;但是进入执行阶段之后,变量对象转换为活动对象,里面的属性都能被访问,然后进行执行阶段的操作;
变量对象和活动对象其实是一个对象,只是处于执行上下文的不同生命周期;
// 执行阶段
VO -> AO
AO = {
arguments: [...],
foo: <foo reference>,
a: 1
}因此上面的代码会变成:
function test() {
function foo() {
return 2;
}
var a;
console.log(a);
console.log(foo());
a = 1;
}
test();1.2.1.1 全局作用域下的变量对象
以浏览器为例,全局对象为window;
全局作用域下有一个特殊的地方,它的变量对象,就是window对象;而这个特殊,在this指向上也同样适用,this也是指向window。
windowEC = {
VO: window,
scopeChain: {},
this: window
}除此之外,全局作用于下的生命周期与程序的生命周期一致;