在前端學習中,作用域這個問題一直被廣泛提起,什么是作用域,什么又是作用域鏈?在Javascript中,怎么去理解這些概念都是學好這門語言的關鍵,所以在學習前端開發的過程中,我需要也很有必要去學習和總結下javascript----作用域。
作用域並不難,但是去很少有人能稍微深入的解釋什么是作用域,知其然而不知其所以然顯然是遠遠不夠的,所以我們就深入淺出一下,
本片博文旨在深度去分析作用域,如有總結不到位之處,請讀者海涵並在評論區指出。
談到作用域就不得不談到一個名詞----執行環境。什么叫執行環境呢?
執行環境是Javascript中最為重要的一個概念,它定義了變量或函數有權訪問其他數據,決定了他們各自的行為。那么在每個執行環境中都有一個叫做“變量對象”的object,執行環境中的所有變量和函數都保存在這個對象中,這個object是無法被訪問到了,它只能在后台被javascript解釋器訪問到。
瀏覽器在解析Javascript代碼的時候會為每個函數創建一個執行環境,並在該執行環境中生成一個變量對象來存儲變量和其內部的函數。我們常常用到的window就是最外圍的執行環境,也叫全局執行環境,每個執行環境的代碼執行完成之后,該環境被銷毀,其中的變量對象也將被銷毀,而全局執行環境只會在瀏覽器或網頁關閉的時候被銷毀,其他的執行環境(或者內部的)則為局部執行環境(函數)。
每個函數都有自己的執行環境,那么當代碼的執行流進入到一個函數時,會將該執行環境推入到一個環境棧中,在函數執行完成之后又將其彈出,把對這個執行環境的控制權交還給之前的執行環境,當代碼在一個執行環境中執行的時候,會將該環境中的變量對象連入到作用域鏈中。作用域鏈的作用就是保證對執行環境中的有權訪問的變量和函數有序的訪問。說到這里,大家可能有些迷糊啦,那么就用點代碼和圖片來解釋下吧。
//window scope var name0 = 'scope0'
console.log(name0) //這里可以訪問到name0 function scope1(){
var name1 = 'scope1'
console.log(name0,name1) //這里可以訪問到name0,name1 function scope2(){ var name2 = 'scope2'
console.log(name0,name1,name2) //這里可以訪問到name0,name1,name2 function scope3(){ var name3 = 'scope3'
console.log(name0,name1,name2,name3) //這里可以訪問到name0,name1,name2,name3 } } }
當JS解釋器去執行這段代碼的時候,會生成4個執行環境,分別是window,scope1,scope2,scope3。然后再執行JS代碼的時候,會把每個執行環境推入到執行棧中,並生成變量對象給連接到作用域鏈中(從上到下),最后生成的作用域鏈就為:
window→scope1→scope2→scope3
對於每個執行環境中的變量對象來說,它的作用域鏈就是它本生加上它之前的變量對象(例如scope2的作用域鏈就是scope2和它之前的scope1和window)。我們先前說道,每個執行環境中的變量對象就是該執行環境能夠訪問到了變量和函數,個人理解為這個函數就是變量對象的作用域鏈上其他的變量對象,那么就很好理解了,我們分析下上面代碼scope2的變量對象上有哪些東西,首先是參數數組(arguments,這里為[])還有name2變量,然后是scope1的變量對象和全局變量對象。
說了這么多,提了那么多概念和名詞,我們好像只是說到了作用域鏈,但是並沒有說到作用域,這不是扯淡嘛!!!!好吧,我們現在就來談談作用域。
還是先來扯下概念吧。是每個執行環境可以通過作用域鏈向上訪問這個他的作用域鏈的其他執行環境,但是不能向下訪問。這個就是作用域啦。。。
還是拿scope2函數來說吧,他可以訪問name2,name1,name0但是不能訪問name3,這個就是作用域的限定,他只能訪問到scope1和window的執行環境(還有它本身)。額,就這么一小段,我自己都醉了,但是個人覺得作用域就這點東西,關鍵的是在與對執行環境、變量對象和作用域鏈的理解。這些才是扎實的理解Javascript作用域的關鍵。
其實說到這里我感覺已經差不多了,第一次寫那么長的博文,文章水准還有待提高,這篇文章主要是我在看《javascript高級程序設計》的看到作用域這小節,感覺作者寫了太好了,於是乎加上了一些個人的理解就寫了這篇博客。非常希望有對WEB開發有深刻理解的大大們提出批評和見解。