執(zhí)行環(huán)境,作用域理解_第1頁(yè)
執(zhí)行環(huán)境,作用域理解_第2頁(yè)
執(zhí)行環(huán)境,作用域理解_第3頁(yè)
執(zhí)行環(huán)境,作用域理解_第4頁(yè)
執(zhí)行環(huán)境,作用域理解_第5頁(yè)
全文預(yù)覽已結(jié)束

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

Javascript學(xué)習(xí)---2、執(zhí)行環(huán)境,作用域作者:名劉天下來(lái)源:博客園發(fā)布時(shí)間:2010-12-1017:03閱讀:155次原文鏈接[收藏]在javascript的學(xué)習(xí)中,執(zhí)行環(huán)境、作用域是2個(gè)非常非常重要和基本的概念,理解了這2個(gè)概念對(duì)于javsacript中很多腳本的運(yùn)行結(jié)果就能明白其中的道理了,比如搞清作用域和執(zhí)行環(huán)境對(duì)于閉包的理解至關(guān)重要。一、執(zhí)行環(huán)境(exectioncontext,也有稱(chēng)之為執(zhí)行上下文)所有JavaScript代碼都是在一個(gè)執(zhí)行環(huán)境中被執(zhí)行的。執(zhí)行環(huán)境是一個(gè)概念,一種機(jī)制,用來(lái)完成JavaScript運(yùn)行時(shí)在作用域、生存期等方面的處理,它定義了變量或函數(shù)是否有權(quán)訪問(wèn)其他數(shù)據(jù),決定各自行為。在javascript中,可執(zhí)行的JavaScript代碼分三種類(lèi)型:1.GlobalCode即全局的、不在任何函數(shù)里面的代碼,例如:一個(gè)js文件、嵌入在HTML頁(yè)面中的js代碼等。EvalCode,即使用eval()函數(shù)動(dòng)態(tài)執(zhí)行的JS代碼。FunctionCode,即用戶自定義函數(shù)中的函數(shù)體JS代碼。不同類(lèi)型的JavaScript代碼具有不同的執(zhí)行環(huán)境,這里我們不考慮evelcode,對(duì)應(yīng)于globalcode和functioncode存在2種執(zhí)行環(huán)境:全局執(zhí)行環(huán)境和函數(shù)執(zhí)行環(huán)境。在一個(gè)頁(yè)面中,第一次載入JS代碼時(shí)創(chuàng)建一個(gè)全局執(zhí)行環(huán)境,全局執(zhí)行環(huán)境是最外圍的執(zhí)行環(huán)境,在Web瀏覽器中,全局執(zhí)行環(huán)境被認(rèn)為是window對(duì)象。因此,所有的全局變量和函數(shù)都是作為window對(duì)象的屬性和方法創(chuàng)建的。當(dāng)調(diào)用一個(gè)JavaScript函數(shù)時(shí),該函數(shù)就會(huì)進(jìn)入與該函數(shù)相對(duì)應(yīng)的執(zhí)行環(huán)境。如果又調(diào)用了另外一個(gè)函數(shù)(或者遞歸地調(diào)用同一個(gè)函數(shù)),則又會(huì)創(chuàng)建一個(gè)新的執(zhí)行環(huán)境,并且在函數(shù)調(diào)用期間執(zhí)行過(guò)程都處于該環(huán)境中。當(dāng)調(diào)用的函數(shù)返回后,執(zhí)行過(guò)程會(huì)返回原始執(zhí)行環(huán)境。因而,運(yùn)行中的JavaScript代碼就構(gòu)成了一個(gè)執(zhí)行環(huán)境棧。Code1:functionFn1(){functionFn2(){alert(document.body.tagName);//BODY//othercode...}Fn2();}Fn1();//codehere(圖1執(zhí)行環(huán)境棧摘自:笨蛋的座右銘的博文)程序在進(jìn)入每個(gè)執(zhí)行環(huán)境的時(shí)候,JavaScript引擎在內(nèi)部創(chuàng)建一個(gè)對(duì)象,叫做變量對(duì)象(VariableObject)。對(duì)應(yīng)函數(shù)的每一個(gè)參數(shù),在VariableObject上添加一個(gè)屬性,屬性的名字、值與參數(shù)的名字、值相同。函數(shù)中每聲明一個(gè)變量,也會(huì)在VariableObject上添加一個(gè)屬性,名字就是變量名,因此為變量賦值就是給VariableObject對(duì)應(yīng)的屬性賦值。在函數(shù)中訪問(wèn)參數(shù)或者局部變量時(shí),就是在variableObject上搜索相應(yīng)的屬性,返回其值。(另外注意:一般情況下VariableObject是一個(gè)內(nèi)部對(duì)象,JS代碼中無(wú)法直接訪問(wèn)。規(guī)范中對(duì)其實(shí)現(xiàn)方式也不做要求,因此它可能只是引擎內(nèi)部的一種數(shù)據(jù)結(jié)構(gòu)。)大致處理方式就這樣,但作用域的概念不只這么簡(jiǎn)單,例如函數(shù)體中可以使用全局變量、函數(shù)嵌套定義時(shí)情況更復(fù)雜點(diǎn)。這些情況下怎樣處理?JavaScript引擎將不同執(zhí)行位置上的VariableObject按照規(guī)則構(gòu)建一個(gè)鏈表,在訪問(wèn)一個(gè)變量時(shí),先在鏈表的第1個(gè)VariableObject上查找,如果沒(méi)有找到則繼續(xù)在第2個(gè)VariableObject上查找,直到搜索結(jié)束。這就是Scope/ScopeChain的大致概念。二、Scope/ScopeChain(作用域/作用域鏈)當(dāng)代碼在一個(gè)環(huán)境中執(zhí)行時(shí),都會(huì)創(chuàng)建基于VariableObject的一個(gè)作用域鏈。作用域鏈的用途是保證對(duì)執(zhí)行環(huán)境有權(quán)訪問(wèn)的所有變量和函數(shù)的有序訪問(wèn)。整個(gè)作用域鏈?zhǔn)怯刹煌瑘?zhí)行位置上的VariableObject按照規(guī)則所構(gòu)建一個(gè)鏈表。作用域鏈的最前端,始終是當(dāng)前正在執(zhí)行的代碼所在環(huán)境的VariableObject。如果這個(gè)環(huán)境是函數(shù)(比如Fn2),則將其活動(dòng)對(duì)象(activationobject)作為變量對(duì)象。活動(dòng)對(duì)象在最開(kāi)始時(shí)只包含一個(gè)變量,就是函數(shù)內(nèi)部的arguments對(duì)象。作用域鏈中的下一個(gè)VariableObject來(lái)自該函數(shù)(Fn2)的包含環(huán)境(也就是Fn1),而再下一個(gè)Variableobject來(lái)自再下一個(gè)包含環(huán)境。這樣,一直延續(xù)到全局執(zhí)行環(huán)境,全局執(zhí)行環(huán)境的VariableObject始終是作用域鏈中的最后一個(gè)對(duì)象。如上所述,作用域鏈感覺(jué)就是一個(gè)VariableObject鏈表,當(dāng)訪問(wèn)一個(gè)變量時(shí),先在鏈表的第一個(gè)VariableObject(最前端)上查找,如果沒(méi)有找到則繼續(xù)在第二個(gè)VariableObject上查找,直到搜索結(jié)束,也就是搜索到全局執(zhí)行環(huán)境的VariableObject中。這也就形成了ScopeChain的概念。與上面Code1代碼對(duì)應(yīng)的作用域鏈圖如下所示(摘自:笨蛋的座右銘的博文,這個(gè)圖感覺(jué)不是很理想,不如下面的圖3更形象,把右側(cè)這部分調(diào)個(gè)個(gè)就好了。)(圖2作用域鏈圖)如上圖所示,對(duì)于Codel代碼中的函數(shù)Fn2所對(duì)應(yīng)的作用域鏈為:Fn2VariableObject->Fn1variableObject->全局對(duì)象。也就是說(shuō),在Fn2函數(shù)中進(jìn)行變量訪問(wèn)時(shí),首先會(huì)在Fn2Variableobject訪問(wèn)內(nèi)進(jìn)行尋找,如果沒(méi)有找到,則向上,搜索Fn1VariableObject中是否存在,直至找到,停止搜索。再拿《javascript高級(jí)程序設(shè)計(jì)第二版》中提到的例子來(lái)說(shuō)明一下。代碼如下所示:Code2:varcolor="blue";functionchangecolor(){varanothercolor="red";functionswapcolors(){vartempcolor=anothercolor;anothercolor=color;color=tempcolor;//Todosomething}swapcolors();}changecolor();〃這里不能訪問(wèn)tempcolor和anocolor;但是可以訪問(wèn)color;alert("Colorisnow"+color);在Code2代碼中,涉及3個(gè)執(zhí)行環(huán)境全局環(huán)境、changecolor函數(shù)的局部環(huán)境和swapcolor局部環(huán)境。該段代碼的作用域鏈如下圖所示。

window《javascript高級(jí)程序設(shè)計(jì)第二版》)colorwindow《javascript高級(jí)程序設(shè)計(jì)第二版》)colorchar)geColor()——mmth略rSlQr——色wwpCcdqr串()I—tempCalcr(圖3摘自:上圖中,.-》全局環(huán)境有1個(gè)變量color和1個(gè)函數(shù)changecolor()。?-》changecolor()函數(shù)的局部環(huán)境中具有1個(gè)anothercolor屬性和1個(gè)swapcolors函數(shù),當(dāng)然,changecolor函數(shù)中可以訪問(wèn)自身以及它外圍(也就是全局環(huán)境)中的變量。?-》swapcolor()函數(shù)的局部環(huán)境中具有1個(gè)變量tempcolor。在該函數(shù)內(nèi)部可以訪問(wèn)上面的2個(gè)環(huán)境(changecolor和window)中的所有變量,因?yàn)槟?個(gè)環(huán)境都是它的父執(zhí)行環(huán)境。通過(guò)上面的分析,我們可以得知內(nèi)部環(huán)境可以通過(guò)作用域鏈訪問(wèn)所有的外部環(huán)境,但外部環(huán)境不能訪問(wèn)內(nèi)部環(huán)境中的任何變量和函數(shù)。這些環(huán)境之間是線性、有次序的。每個(gè)環(huán)境都可以向上搜索作用域鏈,以便查詢變量和函數(shù)名;但任何環(huán)境不能通過(guò)向下搜索作用域鏈條而進(jìn)入另一個(gè)執(zhí)行環(huán)境。對(duì)于上述例子的swapcolor()函數(shù)而言,其作用域鏈包括:swapcolor()的變量對(duì)象、changecolor()變量對(duì)象和全局對(duì)象。swapcolor()的局部環(huán)境開(kāi)始先在自己的VariableObject中搜索變量和函數(shù)名,找不到,則向上搜索changecolor作用域鏈。。。。。以此類(lèi)推。但是,changecolor()函數(shù)是無(wú)法訪問(wèn)swapcolor中的變量。關(guān)于作用域總結(jié)以下幾條:1、javascript沒(méi)有塊級(jí)作用域。直接上代碼:for(vari=0;i<10;i++){doSomething(i);}alert(i);//output:10,why?上述代碼運(yùn)行后會(huì)返回10,為什么呢?如果是同樣的java或是c#代碼,則不會(huì)是10,可能會(huì)提示運(yùn)行錯(cuò)誤,因?yàn)閕只存在于for循環(huán)體重,在運(yùn)行完for循環(huán)后,for中的所有變量就被銷(xiāo)毀了。而在javascript中則不是這樣的,在for中的變量聲明將會(huì)添加到當(dāng)前的執(zhí)行環(huán)境中(這里是全局執(zhí)行環(huán)境),因此在for循環(huán)完后,變量i依舊存在于循環(huán)外部的執(zhí)行環(huán)境。因此,會(huì)輸出10。2、聲明變量使用var聲明變量時(shí),這個(gè)變量將被自動(dòng)添加到距離最近的可用環(huán)境中。對(duì)于函數(shù)而言,自然聲明的變量就會(huì)被添加到函數(shù)的局部環(huán)境中,變量在整個(gè)函數(shù)環(huán)境內(nèi)都是可用的。但是,如果變量沒(méi)有是用var進(jìn)行聲明,將會(huì)被添加到全局環(huán)境,也就是說(shuō)成位全局變量了。所以在函數(shù)體內(nèi),進(jìn)行聲明時(shí),一般要在開(kāi)頭用var進(jìn)行聲明。最后出幾個(gè)小例題:varx=1;functionrain(){alert(x); 〃彈出'undefined',而不是1,也不是10,why?varx='10';alert(x); 〃彈出'10',why?}rain()為什么會(huì)是代碼中所說(shuō)明的結(jié)果呢?我認(rèn)為和2個(gè)事情有關(guān):作用域和預(yù)解析。我們可以很容易得出上述代碼的作用域鏈。window全局環(huán)境和rain()函數(shù)局部環(huán)境。window全局環(huán)境中存在全局變量x和ra

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論