最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript作用域與作用域鏈深入解析

 更新時間:2013年12月06日 10:23:20   作者:  
這篇文章主要是對JavaScript作用域和作用域鏈作簡單的介紹,希望能幫助大家更好的學習JavaScript

作用域是JavaScript最重要的概念之一,想要學好JavaScript就需要理解JavaScript作用域和作用域鏈的工作原理。今天這篇文章對JavaScript作用域和作用域鏈作簡單的介紹,希望能幫助大家更好的學習JavaScript。

JavaScript作用域

任何程序設計語言都有作用域的概念,簡單的說,作用域就是變量與函數(shù)的可訪問范圍,即作用域控制著變量與函數(shù)的可見性和生命周期。在JavaScript中,變量的作用域有全局作用域和局部作用域兩種。

1. 全局作用域(Global Scope)

在代碼中任何地方都能訪問到的對象擁有全局作用域,一般來說一下幾種情形擁有全局作用域:

(1)最外層函數(shù)和在最外層函數(shù)外面定義的變量擁有全局作用域,例如:

復制代碼 代碼如下:

var authorName="山邊小溪";
function doSomething(){
var blogName="";
function innerSay(){
alert(blogName);
}
innerSay();
}
alert(authorName); //山邊小溪
alert(blogName); //腳本錯誤
doSomething(); //
innerSay() //腳本錯誤 

(2)所有末定義直接賦值的變量自動聲明為擁有全局作用域,例如:
復制代碼 代碼如下:

function doSomething(){
var authorName="山邊小溪";
blogName="";
alert(authorName);
}
alert(blogName); //
alert(authorName); //腳本錯誤 

變量blogName擁有全局作用域,而authorName在函數(shù)外部無法訪問到。

(3)所有window對象的屬性擁有全局作用域

一般情況下,window對象的內(nèi)置屬性都都擁有全局作用域,例如window.name、window.location、window.top等等。

2. 局部作用域(Local Scope)

和全局作用域相反,局部作用域一般只在固定的代碼片段內(nèi)可訪問到,最常見的例如函數(shù)內(nèi)部,所有在一些地方也會看到有人把這種作用域成為函數(shù)作用域,例如下列代碼中的blogName和函數(shù)innerSay都只擁有局部作用域。

復制代碼 代碼如下:

function doSomething(){
var blogName="";
function innerSay(){
alert(blogName);
}
innerSay();
}
alert(blogName); //腳本錯誤
innerSay(); //腳本錯誤 

作用域鏈(Scope Chain)

在JavaScript中,函數(shù)也是對象,實際上,JavaScript里一切都是對象。函數(shù)對象和其它對象一樣,擁有可以通過代碼訪問的屬性和一系列僅供JavaScript引擎訪問的內(nèi)部屬性。其中一個內(nèi)部屬性是[[Scope]],由ECMA-262標準第三版定義,該內(nèi)部屬性包含了函數(shù)被創(chuàng)建的作用域中對象的集合,這個集合被稱為函數(shù)的作用域鏈,它決定了哪些數(shù)據(jù)能被函數(shù)訪問。

當一個函數(shù)創(chuàng)建后,它的作用域鏈會被創(chuàng)建此函數(shù)的作用域中可訪問的數(shù)據(jù)對象填充。例如定義下面這樣一個函數(shù):

復制代碼 代碼如下:

function add(num1,num2) {
var sum = num1 + num2;
return sum;


在函數(shù)add創(chuàng)建時,它的作用域鏈中會填入一個全局對象,該全局對象包含了所有全局變量,如下圖所示(注意:圖片只例舉了全部變量中的一部分):


函數(shù)add的作用域?qū)趫?zhí)行時用到。例如執(zhí)行如下代碼:

復制代碼 代碼如下:

var total = add(5,10);

執(zhí)行此函數(shù)時會創(chuàng)建一個稱為“運行期上下文(execution context)”的內(nèi)部對象,運行期上下文定義了函數(shù)執(zhí)行時的環(huán)境。每個運行期上下文都有自己的作用域鏈,用于標識符解析,當運行期上下文被創(chuàng)建時,而它的作用域鏈初始化為當前運行函數(shù)的[[Scope]]所包含的對象。

這些值按照它們出現(xiàn)在函數(shù)中的順序被復制到運行期上下文的作用域鏈中。它們共同組成了一個新的對象,叫“活動對象(activation object)”,該對象包含了函數(shù)的所有局部變量、命名參數(shù)、參數(shù)集合以及this,然后此對象會被推入作用域鏈的前端,當運行期上下文被銷毀,活動對象也隨之銷毀。新的作用域鏈如下圖所示:

在函數(shù)執(zhí)行過程中,沒遇到一個變量,都會經(jīng)歷一次標識符解析過程以決定從哪里獲取和存儲數(shù)據(jù)。該過程從作用域鏈頭部,也就是從活動對象開始搜索,查找同名的標識符,如果找到了就使用這個標識符對應的變量,如果沒找到繼續(xù)搜索作用域鏈中的下一個對象,如果搜索完所有對象都未找到,則認為該標識符未定義。函數(shù)執(zhí)行過程中,每個標識符都要經(jīng)歷這樣的搜索過程。

作用域鏈和代碼優(yōu)化

從作用域鏈的結(jié)構(gòu)可以看出,在運行期上下文的作用域鏈中,標識符所在的位置越深,讀寫速度就會越慢。如上圖所示,因為全局變量總是存在于運行期上下文作用域鏈的最末端,因此在標識符解析的時候,查找全局變量是最慢的。所以,在編寫代碼的時候應盡量少使用全局變量,盡可能使用局部變量。一個好的經(jīng)驗法則是:如果一個跨作用域的對象被引用了一次以上,則先把它存儲到局部變量里再使用。例如下面的代碼:

復制代碼 代碼如下:

function changeColor(){

document.getElementById("btnChange").onclick=function(){

document.getElementById("targetCanvas").style.backgroundColor="red";

};



這個函數(shù)引用了兩次全局變量document,查找該變量必須遍歷整個作用域鏈,直到最后在全局對象中才能找到。這段代碼可以重寫如下:
復制代碼 代碼如下:

function changeColor(){

var doc=document;

doc.getElementById("btnChange").onclick=function(){

doc.getElementById("targetCanvas").style.backgroundColor="red";

};



這段代碼比較簡單,重寫后不會顯示出巨大的性能提升,但是如果程序中有大量的全局變量被從反復訪問,那么重寫后的代碼性能會有顯著改善。

改變作用域鏈

函數(shù)每次執(zhí)行時對應的運行期上下文都是獨一無二的,所以多次調(diào)用同一個函數(shù)就會導致創(chuàng)建多個運行期上下文,當函數(shù)執(zhí)行完畢,執(zhí)行上下文會被銷毀。每一個運行期上下文都和一個作用域鏈關(guān)聯(lián)。一般情況下,在運行期上下文運行的過程中,其作用域鏈只會被 with 語句和 catch 語句影響。

with語句是對象的快捷應用方式,用來避免書寫重復代碼。例如:

復制代碼 代碼如下:

function initUI(){

with(document){

var bd=body,

links=getElementsByTagName("a"),

i=0,

len=links.length;

while(i < len){

update(links[i++]);

}

getElementById("btnInit").onclick=function(){

doSomething();

};

}



這里使用width語句來避免多次書寫document,看上去更高效,實際上產(chǎn)生了性能問題。

當代碼運行到with語句時,運行期上下文的作用域鏈臨時被改變了。一個新的可變對象被創(chuàng)建,它包含了參數(shù)指定的對象的所有屬性。這個對象將被推入作用域鏈的頭部,這意味著函數(shù)的所有局部變量現(xiàn)在處于第二個作用域鏈對象中,因此訪問代價更高了。如下圖所示:


因此在程序中應避免使用with語句,在這個例子中,只要簡單的把document存儲在一個局部變量中就可以提升性能。

另外一個會改變作用域鏈的是try-catch語句中的catch語句。當try代碼塊中發(fā)生錯誤時,執(zhí)行過程會跳轉(zhuǎn)到catch語句,然后把異常對象推入一個可變對象并置于作用域的頭部。在catch代碼塊內(nèi)部,函數(shù)的所有局部變量將會被放在第二個作用域鏈對象中。示例代碼:

復制代碼 代碼如下:

try{

doSomething();

}catch(ex){

alert(ex.message); //作用域鏈在此處改變

}


請注意,一旦catch語句執(zhí)行完畢,作用域鏈機會返回到之前的狀態(tài)。try-catch語句在代碼調(diào)試和異常處理中非常有用,因此不建議完全避免。你可以通過優(yōu)化代碼來減少catch語句對性能的影響。一個很好的模式是將錯誤委托給一個函數(shù)處理,例如:
復制代碼 代碼如下:

try{

doSomething();

}catch(ex){

handleError(ex); //委托給處理器方法



優(yōu)化后的代碼,handleError方法是catch子句中唯一執(zhí)行的代碼。該函數(shù)接收異常對象作為參數(shù),這樣你可以更加靈活和統(tǒng)一的處理錯誤。由于只執(zhí)行一條語句,且沒有局部變量的訪問,作用域鏈的臨時改變就不會影響代碼性能了。

相關(guān)文章

  • 學習JavaScript設計模式(繼承)

    學習JavaScript設計模式(繼承)

    這篇文章主要帶領(lǐng)大家學習JavaScript設計模式,其中重點介紹繼承,舉例說明為什么需要繼承,對繼承進行詳細剖析,感興趣的小伙伴們可以參考一下
    2015-11-11
  • JavaScript位置參數(shù)實現(xiàn)原理及過程解析

    JavaScript位置參數(shù)實現(xiàn)原理及過程解析

    這篇文章主要介紹了JavaScript位置參數(shù)實現(xiàn)原理及過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-09-09
  • JS實現(xiàn)的簡單折疊展開動畫效果示例

    JS實現(xiàn)的簡單折疊展開動畫效果示例

    這篇文章主要介紹了JS實現(xiàn)的簡單折疊展開動畫效果,可實現(xiàn)類似百度頁面分享按鈕一樣的折疊展開動畫效果,涉及javascript頁面元素屬性動態(tài)操作相關(guān)實現(xiàn)技巧,需要的朋友可以參考下
    2018-04-04
  • javaScript 利用閉包模擬對象的私有屬性

    javaScript 利用閉包模擬對象的私有屬性

    JavaScript缺少塊級作用域,沒有private修飾符,但它具有函數(shù)作用域。作用域的好處是內(nèi)部函數(shù)可以訪問它們的外部函數(shù)的參數(shù)和變量(除了this和argument
    2011-12-12
  • JS 學習總結(jié)之正則表達式的懶惰性和貪婪性

    JS 學習總結(jié)之正則表達式的懶惰性和貪婪性

    這篇文章主要介紹了JS 學習總結(jié)之正則表達式的懶惰性和貪婪性的相關(guān)資料,需要的朋友可以參考下
    2017-07-07
  • js右下角彈出提示框示例代碼

    js右下角彈出提示框示例代碼

    這篇文章主要介紹了js右下角彈出提示框示例代碼,即網(wǎng)頁右下角彈出廣告信息框?qū)嵗a,感興趣的小伙伴們可以參考一下
    2016-01-01
  • 前端實現(xiàn)多個內(nèi)容滑動輪播圖效果實例

    前端實現(xiàn)多個內(nèi)容滑動輪播圖效果實例

    在前端開發(fā)中,滑動輪播圖是一種常見的交互元素,用于展示多張圖片或內(nèi)容,這篇文章主要介紹了前端實現(xiàn)多個內(nèi)容滑動輪播圖效果的相關(guān)資料,文中給出了詳細的代碼示例,需要的朋友可以參考下
    2025-04-04
  • javascript實現(xiàn)復制與粘貼操作實例

    javascript實現(xiàn)復制與粘貼操作實例

    這篇文章主要介紹了javascript實現(xiàn)復制與粘貼操作,以實例形式講述了javascript實現(xiàn)復制與粘貼操作的實現(xiàn)方法,需要的朋友可以參考下
    2014-10-10
  • 工作需要寫的一個js拖拽組件

    工作需要寫的一個js拖拽組件

    工作需要寫的一個js拖拽組件,需要的朋友可以參考下代碼。
    2011-07-07
  • 可自定義速度的js圖片無縫滾動示例分享

    可自定義速度的js圖片無縫滾動示例分享

    這篇文章主要介紹了非常平滑的JS圖片滾動特效代碼,無縫循環(huán),速度可自定義,大家參考使用吧
    2014-01-01

最新評論

沿河| 贡山| 高平市| 四子王旗| 鞍山市| 蓝山县| 兴义市| 临泉县| 延长县| 德钦县| 通渭县| 巴里| 于都县| 灵宝市| 老河口市| 石首市| 高雄县| 三穗县| 平昌县| 漠河县| 安塞县| 从江县| 平定县| 崇左市| 石泉县| 沙河市| 东山县| 工布江达县| 九江市| 临潭县| 太和县| 姚安县| 锡林浩特市| 佳木斯市| 贺州市| 台山市| 崇阳县| 井研县| 贞丰县| 巧家县| 同江市|