- EC 函数执行环境(执行上下文),Execution Context
- ECS 执行环境栈,Execution Context Stack
- VO 变量对象 Variable Object (声明时,未执行)
- AO 活动对象 Active Object (声明之后,在执行语句时)
- scope chain 作用域链
EC
- 全局代码:不包括函数体内的代码
- 函数代码:函数体内的代码(不包括函数体内的函数的内部代码)
- Eval代码:Eval内部代码
ECS
函数执行栈,在函数VO时入站,执行完AO时出栈
let a = 'Hello World!';
function first() {
console.log('Inside first function');
second();
console.log('Again inside first function');
}
function second() {
console.log('Inside second function');
}
first();
console.log('Inside Global Execution Context');
首先生命first入栈,之后生命second入栈,之后执行first但是first中执行了second,second执行完出栈,之后执行完first。
VO
在执行上下文时,参数声明,函数声明,变量的声明。
参数声明》函数声明》变量声明如果变量对象已经包含了相同名字的属性,则替换它的值
function foo1(a){
console.log(a)
function a(){}
}
foo1(20)//'function a(){}'
此时console.log(a),已经完成了VO阶段,也就上声明阶段,由于函数后声明,所有输出为函数。如果变量名和已经声明的函数名或者函数的参数名相同,则不会影响已经存在的属性
function foo1(a){
console.log(a)
function a(){}
var a =1;
}
foo1(20)//'function a(){}'
函数的声明比变量优先级要高,并且定义过程不会被变量覆盖,除非是赋值
AO
function foo(i){
var a = 'hello'
var b = function(){}
function c(){}
}
foo(22)
vo阶段
ECObj = {
scopChain: {...},
variableObject: {
arguments: {
0: 22,
length: 1
},
i: 22,
c: pointer to function c()
a: undefined,
b: undefined
},
this: { ... }
}
ao阶段
ECObj = {
scopeChain: { ... },
variableObject: {
arguments: {
0: 22,
length: 1
},
i: 22,
c: pointer to function c()
a: 'hello',
b: pointer to function privateB()
},
this: { ... }
}
此时的console.log(typeof foo); console.log(typeof bar); 在函数的声明之后阶段(vo)
(function() {
console.log(typeof foo); // 函数指针
console.log(typeof bar); // undefined
var foo = 'hello',
bar = function() {
return 'world';
};
function foo() {
return 'hello';
}
}());
此时的console.log()为执行之后阶段(ao)
(function() {
var foo = 'hello',
bar = function() {
return 'world';
};
function foo() {
return 'hello';
}
console.log(typeof foo); // string
console.log(typeof bar); // function
}());