国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
Javascript Closures (2)

Javascript Closures (2)

上一篇文章中,簡單介紹了下閉包(closure)和原型鏈,現(xiàn)在繼續(xù)來研究閉包的內(nèi)部機制。

對了,所有的東西都參考自這篇文章:Javascript Closures

執(zhí)行環(huán)境(Execution Context)

執(zhí)行環(huán)境(Execution Context) 是 ECMAScript 定義中的一個抽象概念,用來定義 ECMAScript執(zhí)行時所需要的一些行為。所有的 JS代碼都是在一個執(zhí)行環(huán)境中被執(zhí)行的,全局的代碼是在一個全局的執(zhí)行環(huán)境中執(zhí)行的,而對函數(shù)的每次調(diào)用都會產(chǎn)生一個相應(yīng)的執(zhí)行環(huán)境。

當(dāng)一個函數(shù)被調(diào)用的時候,就會進入到一個執(zhí)行環(huán)境中,當(dāng)另外一個函數(shù)被調(diào)用(或者同一個函數(shù)被遞歸調(diào)用)的時候就會進入到一個新的執(zhí)行環(huán)境,而且當(dāng)這個函數(shù)返回的時候,就會回到原來的執(zhí)行環(huán)境中。所以,運行中的 JS 代碼會有一個執(zhí)行環(huán)境堆棧。

當(dāng)一個執(zhí)行環(huán)境被創(chuàng)建的時候,會發(fā)生一系列的事情。首先,它會創(chuàng)建一個 “Activation” 對象,不過這個對象很特別,因為它沒有prototype 并且不能在代碼中直接引用。然后就會創(chuàng)建一個叫做 “arguments”類似數(shù)組的對象,里面保存了傳過來的參數(shù),同時”Activation” 對象上會創(chuàng)建一個叫做 “arguments” 的屬性并指向剛剛創(chuàng)建的“arguments”對象。

接下來,執(zhí)行環(huán)境就會被賦予一個作用域(scope)。一個作用域一般是由一系列的對象組成的,每個函數(shù)對象都有一個內(nèi)部的 [[scope]]屬性,該屬性也是由一系列的對象組成的。執(zhí)行環(huán)境被賦予的那個 scope 就會被相應(yīng)函數(shù)對象中的[[scope]]屬性所引用,同時會把開始創(chuàng)建的 “Activation” 對象插入到 scope 包含對象的最前面。

然后,就會使用ECMA 262提到的一個 “Variable” 對象進行變量初始化。事實上,前面創(chuàng)建的 “Activation”對象和這里的”Variable” 對象其實是同一個對象。初始化的時候會在 “Variable”對象上創(chuàng)建一些和函數(shù)定義中的參數(shù)同名的屬性,如果有傳過來的參數(shù),就會把傳過來的值賦給 “Variable”對象上相應(yīng)的屬性(不然就賦值undefined)。如果有內(nèi)部函數(shù),那么就會創(chuàng)建一個函數(shù)對象,然后在 “Variable”對象上創(chuàng)建一個和內(nèi)部函數(shù)名字相同的屬性,并把剛創(chuàng)建的函數(shù)對象賦值給它。變量初始化的最后一步就是在 “Variable”對象上創(chuàng)建和函數(shù)內(nèi)部的聲明的本地變量同名的所有屬性。

其實在變量初始化的時候,所有本地變量對應(yīng)的 “Variable” 對象上的屬性值都是 undefined,它們并沒有被真正初始化。只有當(dāng)執(zhí)行到函數(shù)體內(nèi)對它們賦值的語句的時候,它們才算是真正初始化了。

正是由于 “Activation” 對象和 “Variable” 對象其實是同一個對象,所以在代碼中,”Activation” 對象上的 “arguments” 屬性就可以像本地變量那樣被引用。

最后,會對this關(guān)鍵字賦一個值。如果this被賦值為一個對象,那么以this.為前綴的所有屬性都是指該對象上的屬性,如果this 被賦值為 null ,那么它就指向 global 對象。

全局的執(zhí)行環(huán)境相對于函數(shù)的執(zhí)行環(huán)境來說,有那么一點不同。因為全局執(zhí)行環(huán)境不需要參數(shù),所以它也就不需要創(chuàng)建一個 “Activation”對象來引用它們。全局執(zhí)行環(huán)境也有一個 scope,不過它的 scope只包含一個對象,就是 global對象。它也會經(jīng)過變量初始化,而且global 對象會充當(dāng)其中的 “Variable” 對象 ,這就是為什么在全局作用域聲明的函數(shù)和變量都會作為 global對象的屬性。全局的執(zhí)行環(huán)境中,this關(guān)鍵字指向的也是 global 對象。

scope 鏈 和 [[scope]] 屬性

要了解 scope 鏈,首先需要了解的就是內(nèi)部的 [[scope]] 屬性。在ECMAScript 中,所有的函數(shù)都是對象,在執(zhí)行函數(shù)聲明或者表達式的時候會創(chuàng)建函數(shù)對象,它們也可以通過構(gòu)造函數(shù) Function 被創(chuàng)建。

在通過構(gòu)造函數(shù)Function 來創(chuàng)建函數(shù)對象的時候,這個函數(shù)對象內(nèi)部的 [[scope]] 屬性總是指向一個只包含了global對象的scope鏈。通過聲明或者表達式創(chuàng)建的函數(shù)對象內(nèi)部的[[scope]]屬性則指向其所在的執(zhí)行環(huán)境的scope 鏈。

比如下面兩段代碼:

1
2
3
function exampleFunction(formalParameter)
{ ... // function body code
}
1
2
3
var exampleFuncRef = function(){ 
... // function body code
}

雖然寫法有點不同,函數(shù)對象創(chuàng)建的時間也不同,但是由于它們所處的都是全局的執(zhí)行環(huán)境,所以它們內(nèi)部的[[scope]] 屬性指向的scope 鏈只包含一個 global 對象。

內(nèi)部函數(shù)有一些不同,因為它們是在函數(shù)內(nèi)部定義的,所以執(zhí)行環(huán)境就不是全局執(zhí)行環(huán)境,scope鏈上的對象就比較多??匆幌孪旅娴拇a:

1
2
3
4
5
6
7
8
function exampleOuterFunction(formalParameter){ 
function exampleInnerFuncitonDec(){
... // inner function body
}
... // the rest of the outer function body.
}
 
exampleOuterFunction( 5 );

對于內(nèi)部函數(shù)exampleInnerFuncitonDec()來說,當(dāng)外部函數(shù)被調(diào)用的時候,就創(chuàng)建了一個新的執(zhí)行環(huán)境和相應(yīng)的Activation/Variable對象,所以它內(nèi)部的[[scope]]屬性就指向了當(dāng)前的scope鏈:包含了當(dāng)前執(zhí)行環(huán)境的Activation 對象以及外部函數(shù)的[[scope]] 上的global對象。

由此我們看到,代碼的邏輯和結(jié)構(gòu)會自動控制 scope 鏈的創(chuàng)建。不過ECMAScript提供了一個 with 語句,使用它可以更改scope 鏈。

函數(shù)聲明不會受到 with 語句的影響,因為它們在變量初始化的時候就已經(jīng)創(chuàng)建相應(yīng)的函數(shù)對象了,但是函數(shù)表達式可以,看下面的代碼:

1
2
3
4
5
6
7
8
9
10
var y = {x:5};
function exampleFuncWith(){
var z;
with(y){
z = function(){
... // inner function expression body;
}
}
...
}

由于使用了 with 語句,在函數(shù)執(zhí)行的時候,內(nèi)部函數(shù) z 的 [[scope]] 屬性指向的 scope 鏈的前面又會插入一個 y 對象,變成: y對象->當(dāng)前執(zhí)行環(huán)境的Activation對象->global對象。

接下來看一下標(biāo)識符定位的問題。當(dāng)代碼運行的時候如果發(fā)現(xiàn)了某個標(biāo)識符,就會在scope鏈中的對象上尋找與它對應(yīng)的變量,從第一個開始依次找,如果找到就返回,不然就一直找到 scope 鏈的末尾。由于函數(shù)被調(diào)用的時候會創(chuàng)建新的執(zhí)行環(huán)境,就會把相應(yīng)的Activation/Variable對象插入到 scope 鏈的前面,所以對于函數(shù)體中的標(biāo)識符,總是會先檢查是否有相對應(yīng)的內(nèi)部函數(shù)、參數(shù)或者本地變量。
=============
以上是自己學(xué)到的一些東西,如果有不對的地方,歡迎拍磚。

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
深入理解JavaScript閉包(closure) – Felix Woo
javascript語言中的閉包
JS閉包
JavaScript對象模型-執(zhí)行模型 - Richie - 博客園
JavaScript執(zhí)行環(huán)境+變量對象+作用域鏈+閉包
JavaScript作用域鏈其二:函數(shù)的生命周期
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服