scope
函数在创建时,会添加[[scope]]属性
var x = 3
function parent(){
var x = 4
function kid(){
var x = 5
}
}
parent的[[scope]] = [globalContext.VO]
kid的[[scope]] = [parentConetext.AO,globalContext.VO]
执行上下文 execution context
在运行代码时,首先会创建一个执行上下文栈,假设是一个数组ECStack = [ ].
当javascript执行代码时,首先遇到的是全局执行上下文,所以此时ECStack = [ globalContext ]
只有当程序运行结束时,ECStack才会被清空,否则globalContext会一直在栈底.每当有一个函数运行,就将该函数的执行上下文压人该栈,运行结束时弹出.全局上下文始终在栈尾.
function fun3() {
console.log('fun3')
}
function fun2() {
fun3();
}
function fun1() {
fun2();
}
fun1();
伪代码:
// fun1()
ECStack.push(<fun1> functionContext);
// fun1中竟然调用了fun2,还要创建fun2的执行上下文
ECStack.push(<fun2> functionContext);
// 擦,fun2还调用了fun3!
ECStack.push(<fun3> functionContext);
// fun3执行完毕
ECStack.pop();
// fun2执行完毕
ECStack.pop();
// fun1执行完毕
ECStack.pop();
// javascript接着执行下面的代码,但是ECStack底层永远有个globalContext
- 当函数运行时,会创建一个执行上下文,有this,scope,变量对象三个属性
1. 变量对象(varialbe object)
变量对象是与执行上下文的数据作用域,存储了在上下文中定义的变量和函数声明.
function foo(a) {
var b = 2;
function c() {}
var d = function() {};
b = 3;
}
foo(1);
运行代码至foo(1),时创建该函数的执行上下文,其中的变量对象为
AO = {
arguments: {
0: 1,
lenght: 1
},
a: 1,
b: 3,
c: function(){},
d: reference to FunctionExpression "d"
}
2. 作用域链 scope chain
当函数激活时,将活动对象添加到作用域链的前端
Scope = [AO].concat([[scope]])
3. this
流程图/总结
var scope = "global scope";
function checkscope(){
var scope2 = 'local scope';
return scope2;
}
checkscope();
执行过程如下:
- checkscope 函数被创建,创建内部属性[[scope]]
checkscope.[[scope]] = [
globalContext.VO
];
- 执行 checkscope 函数,创建 checkscope 函数执行上下文,checkscope 函数执行上下文被压入执行上下文栈
ECStack = [
checkscopeContext,
globalContext
];
- checkscope 函数并不立刻执行,开始做准备工作,第一步:复制函数[[scope]]属性创建作用域链
checkscopeContext = {
Scope: checkscope.[[scope]],
}
- 第二步:用 arguments 创建活动对象,随后初始化活动对象,加入形参、函数声明、变量声明
checkscopeContext = {
AO: {
arguments: {
length: 0
},
scope2: undefined
}
}
- 第三步:将活动对象压入 checkscope 作用域链顶端
checkscopeContext = {
AO: {
arguments: {
length: 0
},
scope2: undefined
},
Scope: [AO, [[Scope]]]
}
- 准备工作做完,开始执行函数,随着函数的执行,修改 AO 的属性值
checkscopeContext = {
AO: {
arguments: {
length: 0
},
scope2: 'local scope'
},
Scope: [AO, [[Scope]]]
}
- 查找到 scope2 的值,返回后函数执行完毕,函数上下文从执行上下文栈中弹出
ECStack = [
globalContext
];