javascript的做用域

javascript的做用域是一個重要的知識點,javascript做用域(scope)是經過javascript的做用域鏈(scope chain)來實現的。javascript

javascript做用域html


javascript做用域(scope):簡單的說,就是建立一個函數時在什麼環境下建立的,它控制了javascript代碼運行時變量和函數的訪問範圍。在JavaScript中,變量的做用域有全局做用域和局部做用域兩種。前端

全局做用域(Global Scope)java


在代碼中任何地方都能訪問到的對象擁有全局做用域,注意:全局變量是魔鬼!由於它效率低(後面講到),污染全局環境!通常有一下三種方式獲取全局做用域。瀏覽器

代碼最外層定義的函數和變量擁有全局做用域函數


在代碼的最外層,定義的函數、變量,都是擁有全局做用域的。性能

var a =1;function b(){var a =2;}b();alert(a);//1優化

函數內部不使用var定義的擁有全局做用域this


在函數內部,不使用var定義的變量擁有全局做用域,這是個坑!要注意,不少前端開發工程師不習慣寫var,其實這時候你已經污染了全局做用域!htm

var a =1;function b(){ a =2; c =3;}b();alert(a);//2alert(c);//3


全部window對象的屬性擁有全局做用域


在《正確理解javascript的this關鍵字》中我提到了腳本語言的運行須要宿主,在瀏覽器的全局對象是window,因此全局的變量和函數是window的屬性,而且擁有全局做用域。

function a(){ window.b=1;}a();alert(b);//1

局部做用域(Local Scope)


和全局做用域相反,局部做用域通常只在固定的代碼片斷內可訪問到,最多見的例如函數內部,全部在一些地方也會看到有人把這種做用域稱爲函數做用域。以下面的代碼中b就是一個局部變量,在函數外部是訪問不到的。

var a =function(){var b =1;alert(b);}a();alert(b);//出錯 b undefined

javascript做用域鏈


javascript做用域(scope)是經過javascript的做用域鏈(scope chain)來實現的。javascript函數對象中擁有一個僅供javascript引擎訪問的內部屬性——[[Scope]],[[Scope]]指向一個集合,即爲「做用域鏈(Scope chain)」,它決定了哪些數據能被函數訪問。

var a =1;function fn1(){var a =9;function fn2(){alert(this.a);//1alert(a);//9} fn2();}fn1();

上面代碼的做用域鏈,能夠用下面的圖來表示:


javascript的做用域鏈圖示

做用域鏈與javascript代碼優化


代碼在運行時,變量的查找老是從做用域鏈的底部開始往上查找,若是第一層沒找到,就要從更高一級做用域查找,這樣一直找下去,一直找到全局做用域,若是沒有找到則返回undefined。

從做用域鏈的結構能夠看出,在運行期上下文的做用域鏈中,標識符所在的位置越深,讀寫速度就會越慢。由於全局變量老是存在於運行期上下文做用域鏈的最末端,所以在標識符解析的時候,查找全局變量是最慢的。因此,在編寫代碼的時候應儘可能少使用全局變量,儘量使用局部變量。

一個好的經驗法則是:若是一個跨做用域的對象被引用了一次以上,則先把它存儲到局部變量裏再使用。以下面的代碼:

function changeColor(){ document.getElementById("btnChange").onclick=function(){ document.getElementById("targetCanvas").style.backgroundColor="red";};}

這個函數引用了兩次全局變量document,查找該變量必須遍歷整個做用域鏈,直到最後在全局對象中才能找到。這段代碼能夠重寫以下:

function changeColor(){var doc=document; doc.getElementById("btnChange").onclick=function(){ doc.getElementById("targetCanvas").style.backgroundColor="red";};}

這段代碼比較簡單,重寫後不會顯示出巨大的性能提高,可是若是程序中有大量的全局變量被從反覆訪問,那麼重寫後的代碼性能會有顯著改善。

做用域鏈的延長


當執行流進入下列任何一個語句時,做用域鏈將獲得延長:

try-catch語句的catch塊

with語句



前端添加一個變量對象。對with來講,其變量對象中包含着指定對象的全部屬性和方法所做的變量申明;對catch來講,其變量對象中包含的是被拋出的錯誤對象的申明。這些標量對象都是隻讀的,所以在with和catch語句中申明的變量都會被添加到所在執行環境的變量對象中。

當with和catch語句結束以後,做用域鏈會恢復到原先的狀態。

值得一提的是改變了javascript的做用域鏈以後,代碼效率會下降。拿with語句來講,當代碼運行到with語句時,運行期上下文的做用域鏈臨時被改變了。一個新的可變對象被建立,它包含了參數指定的對象的全部屬性。這個對象將被推入做用域鏈的頭部,這意味着函數的全部局部變量如今處於第二個做用域鏈對象中,所以訪問代價更高了。

繼續閱讀關於javascript的做用域的文章:

javascript的詞法做用域

正確理解javascript的this關鍵字

聲明:文章未聲明爲原創文章,本文連接 http://js8.in/875.html. 轉載請註明轉自 JS8.IN ?

相關文章
相關標籤/搜索