scope
函數(shù)在創(chuàng)建時(shí),會添加[[scope]]屬性
var x = 3
function parent(){
var x = 4
function kid(){
var x = 5
}
}
parent的[[scope]] = [globalContext.VO]
kid的[[scope]] = [parentConetext.AO,globalContext.VO]
執(zhí)行上下文 execution context
在運(yùn)行代碼時(shí),首先會創(chuàng)建一個執(zhí)行上下文棧,假設(shè)是一個數(shù)組ECStack = [ ].
當(dāng)javascript執(zhí)行代碼時(shí),首先遇到的是全局執(zhí)行上下文,所以此時(shí)ECStack = [ globalContext ]
只有當(dāng)程序運(yùn)行結(jié)束時(shí),ECStack才會被清空,否則globalContext會一直在棧底.每當(dāng)有一個函數(shù)運(yùn)行,就將該函數(shù)的執(zhí)行上下文壓人該棧,運(yùn)行結(jié)束時(shí)彈出.全局上下文始終在棧尾.
function fun3() {
console.log('fun3')
}
function fun2() {
fun3();
}
function fun1() {
fun2();
}
fun1();
偽代碼:
// fun1()
ECStack.push(<fun1> functionContext);
// fun1中竟然調(diào)用了fun2挡篓,還要創(chuàng)建fun2的執(zhí)行上下文
ECStack.push(<fun2> functionContext);
// 擦蜡歹,fun2還調(diào)用了fun3!
ECStack.push(<fun3> functionContext);
// fun3執(zhí)行完畢
ECStack.pop();
// fun2執(zhí)行完畢
ECStack.pop();
// fun1執(zhí)行完畢
ECStack.pop();
// javascript接著執(zhí)行下面的代碼,但是ECStack底層永遠(yuǎn)有個globalContext
- 當(dāng)函數(shù)運(yùn)行時(shí),會創(chuàng)建一個執(zhí)行上下文,有this,scope,變量對象三個屬性
1. 變量對象(varialbe object)
變量對象是與執(zhí)行上下文的數(shù)據(jù)作用域,存儲了在上下文中定義的變量和函數(shù)聲明.
function foo(a) {
var b = 2;
function c() {}
var d = function() {};
b = 3;
}
foo(1);
運(yùn)行代碼至foo(1),時(shí)創(chuàng)建該函數(shù)的執(zhí)行上下文,其中的變量對象為
AO = {
arguments: {
0: 1,
lenght: 1
},
a: 1,
b: 3,
c: function(){},
d: reference to FunctionExpression "d"
}
2. 作用域鏈 scope chain
當(dāng)函數(shù)激活時(shí),將活動對象添加到作用域鏈的前端
Scope = [AO].concat([[scope]])
3. this
流程圖/總結(jié)
var scope = "global scope";
function checkscope(){
var scope2 = 'local scope';
return scope2;
}
checkscope();
執(zhí)行過程如下:
- checkscope 函數(shù)被創(chuàng)建,創(chuàng)建內(nèi)部屬性[[scope]]
checkscope.[[scope]] = [
globalContext.VO
];
- 執(zhí)行 checkscope 函數(shù),創(chuàng)建 checkscope 函數(shù)執(zhí)行上下文,checkscope 函數(shù)執(zhí)行上下文被壓入執(zhí)行上下文棧
ECStack = [
checkscopeContext,
globalContext
];
- checkscope 函數(shù)并不立刻執(zhí)行,開始做準(zhǔn)備工作亥贸,第一步:復(fù)制函數(shù)[[scope]]屬性創(chuàng)建作用域鏈
checkscopeContext = {
Scope: checkscope.[[scope]],
}
- 第二步:用 arguments 創(chuàng)建活動對象,隨后初始化活動對象浇垦,加入形參炕置、函數(shù)聲明、變量聲明
checkscopeContext = {
AO: {
arguments: {
length: 0
},
scope2: undefined
}
}
- 第三步:將活動對象壓入 checkscope 作用域鏈頂端
checkscopeContext = {
AO: {
arguments: {
length: 0
},
scope2: undefined
},
Scope: [AO, [[Scope]]]
}
- 準(zhǔn)備工作做完男韧,開始執(zhí)行函數(shù)朴摊,隨著函數(shù)的執(zhí)行,修改 AO 的屬性值
checkscopeContext = {
AO: {
arguments: {
length: 0
},
scope2: 'local scope'
},
Scope: [AO, [[Scope]]]
}
- 查找到 scope2 的值此虑,返回后函數(shù)執(zhí)行完畢甚纲,函數(shù)上下文從執(zhí)行上下文棧中彈出
ECStack = [
globalContext
];