理解Javascript_13_執(zhí)行模型詳解
更新時(shí)間:2010年10月20日 11:10:27 作者:
在《理解Javascript_12_執(zhí)行模型淺析》一文中,我們初步的了解了執(zhí)行上下文與作用域的概念,那么這一篇將深入分析執(zhí)行上下文的構(gòu)建過程,了解執(zhí)行上下文、函數(shù)對(duì)象、作用域三者之間的關(guān)系。
函數(shù)執(zhí)行環(huán)境
簡(jiǎn)單的代碼:
function say(msg,other){
var str = "nobody say:";
this.name = '笨蛋的座右銘';
function method(){};//var method = function(){};
alert(str+msg);
}
say('hello world');
alert(name);//笨蛋的座右銘
當(dāng)調(diào)用say方法時(shí),第一步是創(chuàng)建其執(zhí)行環(huán)境,在創(chuàng)建執(zhí)行環(huán)境的過程中,會(huì)按照定義的先后順序完成一系列操作:
1.首先會(huì)創(chuàng)建一個(gè)'活動(dòng)對(duì)象'(Activation Object)?;顒?dòng)對(duì)象是規(guī)范中規(guī)定的另外一種機(jī)制。之所以稱之為對(duì)象,是因?yàn)樗鼡碛锌稍L問的命名屬性,但是它又不像正常對(duì)象那樣具有原型(至少?zèng)]有預(yù)定義的原型),而且不能通過 JavaScript 代碼直接引用活動(dòng)對(duì)象。
2.為函數(shù)調(diào)用創(chuàng)建執(zhí)行環(huán)境的下一步是創(chuàng)建一個(gè) arguments 對(duì)象,這是一個(gè)類似數(shù)組的對(duì)象,它以整數(shù)索引的數(shù)組成員一一對(duì)應(yīng)地保存著調(diào)用函數(shù)時(shí)所傳遞的參數(shù)。這個(gè)對(duì)象也有 length 和 callee 屬性(更深入的內(nèi)容,請(qǐng)參見《理解Javascript_14_函數(shù)形式參數(shù)與arguments 》)。然后,會(huì)為活動(dòng)對(duì)象創(chuàng)建一個(gè)名為“arguments”的屬性,該屬性引用前面創(chuàng)建的 arguments對(duì)象。
3.接著,為執(zhí)行環(huán)境分配作用域。作用域由對(duì)象列表(鏈)組成。(比較復(fù)雜,請(qǐng)參見:《理解Javascript_15_作用域分配與變量訪問規(guī)則,再送個(gè)閉包》)
4.之后會(huì)發(fā)生由 ECMA 262 中所謂'活動(dòng)對(duì)象'完成的'變量實(shí)例化'(Variable Instatiation)的過程。此時(shí)會(huì)將函數(shù)的形式參數(shù)創(chuàng)建為可變對(duì)象的命名屬性,如果調(diào)用函數(shù)時(shí)傳遞的參數(shù)與形式參數(shù)一致,則將相應(yīng)參數(shù)的值賦給這些命名屬性(否則,會(huì)給命名屬性賦 undefined 值)。對(duì)于定義的內(nèi)部函數(shù),會(huì)以其聲明時(shí)所用名稱為可變對(duì)象創(chuàng)建同名屬性,而相應(yīng)的內(nèi)部函數(shù)則被創(chuàng)建為函數(shù)對(duì)象并指定給該屬性。變量實(shí)例化的最后一步是將在函數(shù)內(nèi)部聲明的所有局部變量創(chuàng)建為可變對(duì)象的命名屬性。注:在這個(gè)過程中,除了實(shí)際參數(shù)有值外和函數(shù)定義外,其它都被'預(yù)解析'為undefined值.
5.最后,要為使用 this 關(guān)鍵字而賦值。(此時(shí)的this指向的是全局對(duì)象,即window)
執(zhí)行環(huán)境創(chuàng)建成功后,就進(jìn)入第二步:在函數(shù)體內(nèi),從上到下執(zhí)行代碼。
1.當(dāng)執(zhí)行到var str='nobody say'會(huì)發(fā)生稱之為'計(jì)算賦值表達(dá)式'的過程,此時(shí),會(huì)將活動(dòng)對(duì)象中key為str的值從undefined設(shè)置為'nobody say:'。
2.執(zhí)行到this.name='笨蛋的座右銘'時(shí),會(huì)為作為this的對(duì)象添加屬性name,并賦值為'笨蛋的座右銘'.
3.然后是執(zhí)行function innerMethod(){};最后執(zhí)行'alert(str+msg),輸出'nobody say:hello world'.
function method(){}與var method = function(){}的區(qū)別
簡(jiǎn)單的代碼:
function say(){
method01();//method01
method02();//error
function method01(){
alert('method01');
}
var method02 = function(){
alert('method02');
}
}
say();
為什么調(diào)用方法method01能正常運(yùn)行,而調(diào)用方法method02卻會(huì)報(bào)錯(cuò)呢?
首先,你要明確的知道m(xù)ethod01為一個(gè)函數(shù)對(duì)象,而method02為一個(gè)變量,它指向于另一個(gè)函數(shù)對(duì)象。根據(jù)上一節(jié)的內(nèi)容,在'活動(dòng)對(duì)象'完成的'變量實(shí)例化'(Variable Instatiation)的過程中,對(duì)函數(shù)method01進(jìn)行了正常的'預(yù)解析',而對(duì)于變量method02解析為undefined值,當(dāng)進(jìn)入到執(zhí)行代碼的環(huán)節(jié)時(shí),因?yàn)閙ethod02的調(diào)用在其計(jì)算函數(shù)表達(dá)式之前,因此將undefined當(dāng)作方法調(diào)來用,必然會(huì)報(bào)錯(cuò)。解決方案比較簡(jiǎn)單,就是將var method02=function(){...}放到其method02()的調(diào)用之前就可以了或者是用函數(shù)聲明的方式定義函數(shù)(function method(){...})。
注:計(jì)算函數(shù)表達(dá)式就是指程序執(zhí)行到var method02 = function(){...}。method02此時(shí)真正指向一個(gè)函數(shù)對(duì)象。因?yàn)樵?預(yù)解析'時(shí),method02只被賦于了undefined.
全局執(zhí)行環(huán)境(《執(zhí)行模型淺析》中已經(jīng)講過,不再深入)
在一個(gè)頁(yè)面中,第一次載入JS代碼時(shí)創(chuàng)建一個(gè)全局執(zhí)行環(huán)境,全局執(zhí)行環(huán)境的作用域鏈實(shí)際上只由一個(gè)對(duì)象,即全局對(duì)象(window),在開始JavaScript代碼的執(zhí)行之前,引擎會(huì)創(chuàng)建好這個(gè)Scope Chain結(jié)構(gòu)。全局執(zhí)行環(huán)境也會(huì)有變量實(shí)例化的過程,它的內(nèi)部函數(shù)就是涉及大部分 JavaScript 代碼的、常規(guī)的頂級(jí)函數(shù)聲明。而且,在變量實(shí)例化過程中全局對(duì)象就是可變對(duì)象,這就是為什么全局性聲明的函數(shù)是全局對(duì)象屬性的原因。全局性聲明的變量同樣如此全局執(zhí)行環(huán)境會(huì)使用 this 對(duì)象來引用全局對(duì)象。
注:區(qū)別'函數(shù)執(zhí)行環(huán)境'中的活動(dòng)對(duì)象(Activation Object)和全局執(zhí)行環(huán)境中的可變對(duì)象(Vriable Object),Variable Object也叫做Activation Object(因?yàn)橛幸恍┎町惔嬖?,所以?guī)范中重新取一個(gè)名字以示區(qū)別,全局執(zhí)行環(huán)境/Eval執(zhí)行環(huán)境中叫Variable Object,函數(shù)執(zhí)行環(huán)境中就叫做Activation Object)。
Eval執(zhí)行環(huán)境
構(gòu)建Eval執(zhí)行環(huán)境時(shí)的可變對(duì)象(Variable Object)就是調(diào)用eval時(shí)當(dāng)前執(zhí)行上下文中的可變對(duì)象(Variable Object)。在全局執(zhí)行環(huán)境中調(diào)用eval函數(shù),它的可變對(duì)象(Variable Object)就是全局對(duì)象;在函數(shù)中調(diào)用eval,它的可變對(duì)象(Variable Object)就是函數(shù)的活動(dòng)對(duì)象(Activation Object)。
//Passed in FF2.0, IE7, Opera9.25, Safari3.0.4
function fn(arg){
var innerVar = "variable in function";
eval(' \
var evalVar = "variable in eval"; \
document.write(arg + "<br />"); \
document.write(innerVar + "<br />"); \
');
document.write(evalVar);
}
fn("arguments for function");
輸出結(jié)果是:
arguments for function
variable in function
variable in eval
說明: eval調(diào)用中可以訪問函數(shù)fn的參數(shù)、局部變量;在eval中定義的局部變量在函數(shù)fn中也可以訪問,因?yàn)樗鼈兊腣arible Object是同一個(gè)對(duì)象。
進(jìn)入Eval Code執(zhí)行時(shí)會(huì)創(chuàng)建一個(gè)新的Scope Chain,內(nèi)容與當(dāng)前執(zhí)行上下文的Scope Chain完全一樣。
最后的實(shí)例
代碼如下:
var outerVar1="variable in global code";
function fn1(arg1, arg2){
var innerVar1="variable in function code";
function fn2() { return outerVar1+" - "+innerVar1+" - "+" - "+(arg1 + arg2); }
return fn2();
}
var outerVar2=fn1(10, 20);
執(zhí)行處理過程大致如下:
1. 初始化Global Object即window對(duì)象,Variable Object為window對(duì)象本身。創(chuàng)建Scope Chain對(duì)象,假設(shè)為scope_1,其中只包含window對(duì)象。
2. 掃描JS源代碼(讀入源代碼、可能有詞法語(yǔ)法分析過程),從結(jié)果中可以得到定義的變量名、函數(shù)對(duì)象。按照掃描順序:
2.1 發(fā)現(xiàn)變量outerVar1,在window對(duì)象上添加outerVar1屬性,值為undefined;
2.2 發(fā)現(xiàn)函數(shù)fn1的定義,使用這個(gè)定義創(chuàng)建函數(shù)對(duì)象,傳給創(chuàng)建過程的Scope Chain為scope_1。將結(jié)果添加到window的屬性中,名字為fn1,值為返回的函數(shù)對(duì)象。注意fn1的內(nèi)部[[Scope]]就是 scope_1。另外注意,創(chuàng)建過程并不會(huì)對(duì)函數(shù)體中的JS代碼做特殊處理,可以理解為只是將函數(shù)體JS代碼的掃描結(jié)果保存在函數(shù)對(duì)象的內(nèi)部屬性上,在函數(shù)執(zhí)行時(shí)再做進(jìn)一步處理。這對(duì)理解Function Code,尤其是嵌套函數(shù)定義中的Variable Instantiation很關(guān)鍵;
2.3 發(fā)現(xiàn)變量outerVar2,在window對(duì)象上添加outerVar2屬性,值為undefined;
3. 執(zhí)行outerVar1賦值語(yǔ)句,賦值為"variable in global code"。
4. 執(zhí)行函數(shù)fn1,得到返回值:
4.1 創(chuàng)建Activation Object,假設(shè)為activation_1;創(chuàng)建一個(gè)新的Scope Chain,假設(shè)為scope_2,scope_2中第一個(gè)對(duì)象為activation_1,第二個(gè)對(duì)象為window對(duì)象(取自fn1的 [[Scope]],即scope_1中的內(nèi)容);
4.2 處理參數(shù)列表。在activation_1上設(shè)置屬性arg1、arg2,值分別為10、20。創(chuàng)建arguments對(duì)象并進(jìn)行設(shè)置,將arguments設(shè)置為activation_1的屬性;
4.3 對(duì)fn1的函數(shù)體執(zhí)行類似步驟2的處理過程:
4.3.1 發(fā)現(xiàn)變量innerVar1,在activation_1對(duì)象上添加innerVar1屬性,值為undefine;
4.3.2 發(fā)現(xiàn)函數(shù)fn2的定義,使用這個(gè)定義創(chuàng)建函數(shù)對(duì)象,傳給創(chuàng)建過程的Scope Chain為scope_2(函數(shù)fn1的Scope Chain為當(dāng)前執(zhí)行上下文的內(nèi)容)。將結(jié)果添加到activation_1的屬性中,名字為fn2,值為返回的函數(shù)對(duì)象。注意fn2的內(nèi)部 [[Scope]]就是scope_2;
4.4 執(zhí)行innerVar1賦值語(yǔ)句,賦值為"variable in function code"。
4.5 執(zhí)行fn2:
4.5.1 創(chuàng)建Activation Object,假設(shè)為activation_2;創(chuàng)建一個(gè)新的Scope Chain,假設(shè)為scope_3,scope_3中第一個(gè)對(duì)象為activation_2,接下來的對(duì)象依次為activation_1、window 對(duì)象(取自fn2的[[Scope]],即scope_2);
4.5.2 處理參數(shù)列表。因?yàn)閒n2沒有參數(shù),所以只用創(chuàng)建arguments對(duì)象并設(shè)置為activation_2的屬性。
4.5.3 對(duì)fn2的函數(shù)體執(zhí)行類似步驟2的處理過程,沒有發(fā)現(xiàn)變量定義和函數(shù)聲明。
4.5.4 執(zhí)行函數(shù)體。對(duì)任何一個(gè)變量引用,從scope_3上進(jìn)行搜索,這個(gè)示例中,outerVar1將在window上找到;innerVar1、arg1、arg2將在activation_1上找到。
4.5.5 丟棄scope_3、activation_2(指它們可以被垃圾回收了)。
4.5.6 返回fn2的返回值。
4.6 丟棄activation_1、scope_2。
4.7 返回結(jié)果。
5. 將結(jié)果賦值給outerVar2。
參考:
http://www.cnblogs.com/RicCC/archive/2008/02/15/JavaScript-Object-Model-Execution-Model.html
http://www.cn-cuckoo.com/2007/08/01/understand-javascript-closures-72.html
簡(jiǎn)單的代碼:
復(fù)制代碼 代碼如下:
function say(msg,other){
var str = "nobody say:";
this.name = '笨蛋的座右銘';
function method(){};//var method = function(){};
alert(str+msg);
}
say('hello world');
alert(name);//笨蛋的座右銘
當(dāng)調(diào)用say方法時(shí),第一步是創(chuàng)建其執(zhí)行環(huán)境,在創(chuàng)建執(zhí)行環(huán)境的過程中,會(huì)按照定義的先后順序完成一系列操作:
1.首先會(huì)創(chuàng)建一個(gè)'活動(dòng)對(duì)象'(Activation Object)?;顒?dòng)對(duì)象是規(guī)范中規(guī)定的另外一種機(jī)制。之所以稱之為對(duì)象,是因?yàn)樗鼡碛锌稍L問的命名屬性,但是它又不像正常對(duì)象那樣具有原型(至少?zèng)]有預(yù)定義的原型),而且不能通過 JavaScript 代碼直接引用活動(dòng)對(duì)象。
2.為函數(shù)調(diào)用創(chuàng)建執(zhí)行環(huán)境的下一步是創(chuàng)建一個(gè) arguments 對(duì)象,這是一個(gè)類似數(shù)組的對(duì)象,它以整數(shù)索引的數(shù)組成員一一對(duì)應(yīng)地保存著調(diào)用函數(shù)時(shí)所傳遞的參數(shù)。這個(gè)對(duì)象也有 length 和 callee 屬性(更深入的內(nèi)容,請(qǐng)參見《理解Javascript_14_函數(shù)形式參數(shù)與arguments 》)。然后,會(huì)為活動(dòng)對(duì)象創(chuàng)建一個(gè)名為“arguments”的屬性,該屬性引用前面創(chuàng)建的 arguments對(duì)象。
3.接著,為執(zhí)行環(huán)境分配作用域。作用域由對(duì)象列表(鏈)組成。(比較復(fù)雜,請(qǐng)參見:《理解Javascript_15_作用域分配與變量訪問規(guī)則,再送個(gè)閉包》)
4.之后會(huì)發(fā)生由 ECMA 262 中所謂'活動(dòng)對(duì)象'完成的'變量實(shí)例化'(Variable Instatiation)的過程。此時(shí)會(huì)將函數(shù)的形式參數(shù)創(chuàng)建為可變對(duì)象的命名屬性,如果調(diào)用函數(shù)時(shí)傳遞的參數(shù)與形式參數(shù)一致,則將相應(yīng)參數(shù)的值賦給這些命名屬性(否則,會(huì)給命名屬性賦 undefined 值)。對(duì)于定義的內(nèi)部函數(shù),會(huì)以其聲明時(shí)所用名稱為可變對(duì)象創(chuàng)建同名屬性,而相應(yīng)的內(nèi)部函數(shù)則被創(chuàng)建為函數(shù)對(duì)象并指定給該屬性。變量實(shí)例化的最后一步是將在函數(shù)內(nèi)部聲明的所有局部變量創(chuàng)建為可變對(duì)象的命名屬性。注:在這個(gè)過程中,除了實(shí)際參數(shù)有值外和函數(shù)定義外,其它都被'預(yù)解析'為undefined值.
5.最后,要為使用 this 關(guān)鍵字而賦值。(此時(shí)的this指向的是全局對(duì)象,即window)
執(zhí)行環(huán)境創(chuàng)建成功后,就進(jìn)入第二步:在函數(shù)體內(nèi),從上到下執(zhí)行代碼。
1.當(dāng)執(zhí)行到var str='nobody say'會(huì)發(fā)生稱之為'計(jì)算賦值表達(dá)式'的過程,此時(shí),會(huì)將活動(dòng)對(duì)象中key為str的值從undefined設(shè)置為'nobody say:'。
2.執(zhí)行到this.name='笨蛋的座右銘'時(shí),會(huì)為作為this的對(duì)象添加屬性name,并賦值為'笨蛋的座右銘'.
3.然后是執(zhí)行function innerMethod(){};最后執(zhí)行'alert(str+msg),輸出'nobody say:hello world'.
function method(){}與var method = function(){}的區(qū)別
簡(jiǎn)單的代碼:
復(fù)制代碼 代碼如下:
function say(){
method01();//method01
method02();//error
function method01(){
alert('method01');
}
var method02 = function(){
alert('method02');
}
}
say();
為什么調(diào)用方法method01能正常運(yùn)行,而調(diào)用方法method02卻會(huì)報(bào)錯(cuò)呢?
首先,你要明確的知道m(xù)ethod01為一個(gè)函數(shù)對(duì)象,而method02為一個(gè)變量,它指向于另一個(gè)函數(shù)對(duì)象。根據(jù)上一節(jié)的內(nèi)容,在'活動(dòng)對(duì)象'完成的'變量實(shí)例化'(Variable Instatiation)的過程中,對(duì)函數(shù)method01進(jìn)行了正常的'預(yù)解析',而對(duì)于變量method02解析為undefined值,當(dāng)進(jìn)入到執(zhí)行代碼的環(huán)節(jié)時(shí),因?yàn)閙ethod02的調(diào)用在其計(jì)算函數(shù)表達(dá)式之前,因此將undefined當(dāng)作方法調(diào)來用,必然會(huì)報(bào)錯(cuò)。解決方案比較簡(jiǎn)單,就是將var method02=function(){...}放到其method02()的調(diào)用之前就可以了或者是用函數(shù)聲明的方式定義函數(shù)(function method(){...})。
注:計(jì)算函數(shù)表達(dá)式就是指程序執(zhí)行到var method02 = function(){...}。method02此時(shí)真正指向一個(gè)函數(shù)對(duì)象。因?yàn)樵?預(yù)解析'時(shí),method02只被賦于了undefined.
全局執(zhí)行環(huán)境(《執(zhí)行模型淺析》中已經(jīng)講過,不再深入)
在一個(gè)頁(yè)面中,第一次載入JS代碼時(shí)創(chuàng)建一個(gè)全局執(zhí)行環(huán)境,全局執(zhí)行環(huán)境的作用域鏈實(shí)際上只由一個(gè)對(duì)象,即全局對(duì)象(window),在開始JavaScript代碼的執(zhí)行之前,引擎會(huì)創(chuàng)建好這個(gè)Scope Chain結(jié)構(gòu)。全局執(zhí)行環(huán)境也會(huì)有變量實(shí)例化的過程,它的內(nèi)部函數(shù)就是涉及大部分 JavaScript 代碼的、常規(guī)的頂級(jí)函數(shù)聲明。而且,在變量實(shí)例化過程中全局對(duì)象就是可變對(duì)象,這就是為什么全局性聲明的函數(shù)是全局對(duì)象屬性的原因。全局性聲明的變量同樣如此全局執(zhí)行環(huán)境會(huì)使用 this 對(duì)象來引用全局對(duì)象。
注:區(qū)別'函數(shù)執(zhí)行環(huán)境'中的活動(dòng)對(duì)象(Activation Object)和全局執(zhí)行環(huán)境中的可變對(duì)象(Vriable Object),Variable Object也叫做Activation Object(因?yàn)橛幸恍┎町惔嬖?,所以?guī)范中重新取一個(gè)名字以示區(qū)別,全局執(zhí)行環(huán)境/Eval執(zhí)行環(huán)境中叫Variable Object,函數(shù)執(zhí)行環(huán)境中就叫做Activation Object)。
Eval執(zhí)行環(huán)境
構(gòu)建Eval執(zhí)行環(huán)境時(shí)的可變對(duì)象(Variable Object)就是調(diào)用eval時(shí)當(dāng)前執(zhí)行上下文中的可變對(duì)象(Variable Object)。在全局執(zhí)行環(huán)境中調(diào)用eval函數(shù),它的可變對(duì)象(Variable Object)就是全局對(duì)象;在函數(shù)中調(diào)用eval,它的可變對(duì)象(Variable Object)就是函數(shù)的活動(dòng)對(duì)象(Activation Object)。
復(fù)制代碼 代碼如下:
//Passed in FF2.0, IE7, Opera9.25, Safari3.0.4
function fn(arg){
var innerVar = "variable in function";
eval(' \
var evalVar = "variable in eval"; \
document.write(arg + "<br />"); \
document.write(innerVar + "<br />"); \
');
document.write(evalVar);
}
fn("arguments for function");
輸出結(jié)果是:
arguments for function
variable in function
variable in eval
說明: eval調(diào)用中可以訪問函數(shù)fn的參數(shù)、局部變量;在eval中定義的局部變量在函數(shù)fn中也可以訪問,因?yàn)樗鼈兊腣arible Object是同一個(gè)對(duì)象。
進(jìn)入Eval Code執(zhí)行時(shí)會(huì)創(chuàng)建一個(gè)新的Scope Chain,內(nèi)容與當(dāng)前執(zhí)行上下文的Scope Chain完全一樣。
最后的實(shí)例
代碼如下:
復(fù)制代碼 代碼如下:
var outerVar1="variable in global code";
function fn1(arg1, arg2){
var innerVar1="variable in function code";
function fn2() { return outerVar1+" - "+innerVar1+" - "+" - "+(arg1 + arg2); }
return fn2();
}
var outerVar2=fn1(10, 20);
執(zhí)行處理過程大致如下:
1. 初始化Global Object即window對(duì)象,Variable Object為window對(duì)象本身。創(chuàng)建Scope Chain對(duì)象,假設(shè)為scope_1,其中只包含window對(duì)象。
2. 掃描JS源代碼(讀入源代碼、可能有詞法語(yǔ)法分析過程),從結(jié)果中可以得到定義的變量名、函數(shù)對(duì)象。按照掃描順序:
2.1 發(fā)現(xiàn)變量outerVar1,在window對(duì)象上添加outerVar1屬性,值為undefined;
2.2 發(fā)現(xiàn)函數(shù)fn1的定義,使用這個(gè)定義創(chuàng)建函數(shù)對(duì)象,傳給創(chuàng)建過程的Scope Chain為scope_1。將結(jié)果添加到window的屬性中,名字為fn1,值為返回的函數(shù)對(duì)象。注意fn1的內(nèi)部[[Scope]]就是 scope_1。另外注意,創(chuàng)建過程并不會(huì)對(duì)函數(shù)體中的JS代碼做特殊處理,可以理解為只是將函數(shù)體JS代碼的掃描結(jié)果保存在函數(shù)對(duì)象的內(nèi)部屬性上,在函數(shù)執(zhí)行時(shí)再做進(jìn)一步處理。這對(duì)理解Function Code,尤其是嵌套函數(shù)定義中的Variable Instantiation很關(guān)鍵;
2.3 發(fā)現(xiàn)變量outerVar2,在window對(duì)象上添加outerVar2屬性,值為undefined;
3. 執(zhí)行outerVar1賦值語(yǔ)句,賦值為"variable in global code"。
4. 執(zhí)行函數(shù)fn1,得到返回值:
4.1 創(chuàng)建Activation Object,假設(shè)為activation_1;創(chuàng)建一個(gè)新的Scope Chain,假設(shè)為scope_2,scope_2中第一個(gè)對(duì)象為activation_1,第二個(gè)對(duì)象為window對(duì)象(取自fn1的 [[Scope]],即scope_1中的內(nèi)容);
4.2 處理參數(shù)列表。在activation_1上設(shè)置屬性arg1、arg2,值分別為10、20。創(chuàng)建arguments對(duì)象并進(jìn)行設(shè)置,將arguments設(shè)置為activation_1的屬性;
4.3 對(duì)fn1的函數(shù)體執(zhí)行類似步驟2的處理過程:
4.3.1 發(fā)現(xiàn)變量innerVar1,在activation_1對(duì)象上添加innerVar1屬性,值為undefine;
4.3.2 發(fā)現(xiàn)函數(shù)fn2的定義,使用這個(gè)定義創(chuàng)建函數(shù)對(duì)象,傳給創(chuàng)建過程的Scope Chain為scope_2(函數(shù)fn1的Scope Chain為當(dāng)前執(zhí)行上下文的內(nèi)容)。將結(jié)果添加到activation_1的屬性中,名字為fn2,值為返回的函數(shù)對(duì)象。注意fn2的內(nèi)部 [[Scope]]就是scope_2;
4.4 執(zhí)行innerVar1賦值語(yǔ)句,賦值為"variable in function code"。
4.5 執(zhí)行fn2:
4.5.1 創(chuàng)建Activation Object,假設(shè)為activation_2;創(chuàng)建一個(gè)新的Scope Chain,假設(shè)為scope_3,scope_3中第一個(gè)對(duì)象為activation_2,接下來的對(duì)象依次為activation_1、window 對(duì)象(取自fn2的[[Scope]],即scope_2);
4.5.2 處理參數(shù)列表。因?yàn)閒n2沒有參數(shù),所以只用創(chuàng)建arguments對(duì)象并設(shè)置為activation_2的屬性。
4.5.3 對(duì)fn2的函數(shù)體執(zhí)行類似步驟2的處理過程,沒有發(fā)現(xiàn)變量定義和函數(shù)聲明。
4.5.4 執(zhí)行函數(shù)體。對(duì)任何一個(gè)變量引用,從scope_3上進(jìn)行搜索,這個(gè)示例中,outerVar1將在window上找到;innerVar1、arg1、arg2將在activation_1上找到。
4.5.5 丟棄scope_3、activation_2(指它們可以被垃圾回收了)。
4.5.6 返回fn2的返回值。
4.6 丟棄activation_1、scope_2。
4.7 返回結(jié)果。
5. 將結(jié)果賦值給outerVar2。
參考:
http://www.cnblogs.com/RicCC/archive/2008/02/15/JavaScript-Object-Model-Execution-Model.html
http://www.cn-cuckoo.com/2007/08/01/understand-javascript-closures-72.html
相關(guān)文章
封裝的dialog插件 基于bootstrap模態(tài)對(duì)話框的簡(jiǎn)單擴(kuò)展
這篇文章主要介紹了基于bootstrap模態(tài)對(duì)話框的簡(jiǎn)單擴(kuò)展,bootstrap-mzDialog插件的封裝,感興趣的小伙伴們可以參考一下2016-08-08解決OneThink中無法異步提交kindeditor文本框中修改后的內(nèi)容方法
下面小編就為大家?guī)硪黄鉀QOneThink中無法異步提交kindeditor文本框中修改后的內(nèi)容方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-05-05微信小程序?qū)崿F(xiàn)授權(quán)登錄之獲取用戶信息
這篇文章主要介紹了微信小程序?qū)崿F(xiàn)授權(quán)登錄之獲取用戶信息,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05原生JS版和jquery版實(shí)現(xiàn)checkbox的全選/全不選/點(diǎn)選/行內(nèi)點(diǎn)選(Mr.Think)
腳本之家小編之前整理不少checkbox全選全不選這方便的文章,但看了這篇以后發(fā)現(xiàn)實(shí)現(xiàn)方法更好2016-10-10webpack構(gòu)建vue項(xiàng)目的詳細(xì)教程(配置篇)
本篇文章主要介紹了webpack構(gòu)建vue項(xiàng)目的詳細(xì)教程(配置篇),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-07-07