學習前端也有一段時間了,覺得自己可以與大家分享一些我當初遇到疑惑的東西,希望能給對此問題有疑惑的朋友帶來一點幫助。
先來普及一下JS的概念(不要嫌我啰嗦,可能一些朋友開始學習JS是跟着視頻和寫好的代碼學的,應該有一部分對它的結構或者說它的歷史還不太了解),JavaScript由三種東西組成,一個叫ECMAScript,一個叫DOM,還有一個叫BOM,我們現在說的JS其實是它的核心——ECMAScript,簡稱ES。如今市面上的瀏覽器大部分是運行的ES5,但有一些也支持ES6,某些技術大牛都是用ES6編程然后轉ES5,工具是Babel。但我們現在首要學習的還是ES5,只有深入理解了ES5才能做好其他事情。
言歸正傳,今天我們談的是ES5里面的作用域鏈和原型鏈,當時我學習這一章的時候也是比較害怕的,因為以前學習生物的時候啊,什么DNA鏈啊生物鏈啊,就感覺特復雜,對鏈這個玩意有種“一朝被蛇咬十年怕井繩”的感覺。后來在不斷地學習與編碼過程中呢,我逐步的理解了這一些東西,也感謝一些前輩們的文獻與代碼。
說到底作用域鏈,顧名思義,它是與作用域在一起的,何為作用域,我們知道JS里的function,它是用來聲明一個函數的,每一個函數運行的時候會擁有一個自己的執行環境,每個執行環境都能擁有一個位置來存儲這個環境里面定義的變量和函數,當這個執行環境的所有代碼執行完了之后,該環境被銷毀,保存在其中的所有變量和函數定義也被銷毀掉了,我們可以把這一個執行環境稱為一個作用域。(這里值得一提的是ES5沒有塊級作用域的概念,只有函數里面的東西運行完會被銷毀,不在函數里的東西,比如for(var i=0;i<10,i++)這個i不在函數里,而是在一個全局的循環中,它就是一個全局變量。這些問題一些大公司正在協商解決,ES6里大體上已經優化的很好了)
說完了作用域,我們就可以來講講作用域鏈了,作用域鏈是單向的。全局window是最大的作用域,全局里聲明的函數是次一級的作用域,這樣的函數里面可以訪問到全局里的各種變量和函數,但在全局中訪問不到這個函數里面的函數和變量;這樣次一級里面的函數是再次一級,它同樣也是可以訪問上一級和全局的函數與變量,而上級訪問不到這個里面的東西,這樣一層一層的遞進,就成了一條鏈子,也就是作用域鏈;
我們看一串代碼:
1 <!DOCTYPE html> 2 <html> 3 4 <head> 5 <meta charset="UTF-8"> 6 <title></title> 7 </head> 8 9 <body> 10 <script type="text/javascript"> 11 var idol = "J.J"; 12 13 function writeIdol() { 14 console.log("我的偶像是" + idol); //J.J(可以訪問11行全局的idol) 15 idol = "eason"; //修改了11行idol的值 16 function askAnotherIdol() { 17 var anotherIdol = "echo"; 18 console.log("我的偶像是" + idol); //15行“eason” 19 console.log("其他的偶像有" + anotherIdol) //17行“echo” 20 } 21 askAnotherIdol(); 22 console.log("我的偶像是" + idol); //這個時候得到的是15行“eason” 23 console.log("其他的偶像有" + anotherIdol) //得不到了,因為作用域鏈是單向的 24 } 25 writeIdol(); 26 //執行順序為:writeIdol函數執行==>輸出idol(“J.J”)==>修改idol為"eason"==>執行askAnotherIdol函數 27 //==>在函數內部聲明新變量anotherIdol值為"echo",輸出全局idol(已修改“eason”)==>輸出其他的偶像有“echo” 28 //==>輸出全局idol(已修改“eason”)==>輸出anotherIdol(anotherIdol is not defined,因為作用域鏈的單向) 29 </script> 30 </body> 31 32 </html>
作用域鏈可以通過這個例子來理解,通俗點,大魚吃小魚,小魚吃蝦米——大魚可以吃小魚,小魚卻吃不了大魚。我們可以把全局當成蝦米,最里面的函數當大魚就好啦,雖然理解起來有點奇怪,如果沒有自己的理解方式,這樣套用一下也是可以的嘛。
作者也是第一次寫博客,如果寫的不太好或者有疑惑的,歡迎大家提出建議和問題,因為要吃飯啦,本篇就先寫個我對作用域鏈的理解吧,原型鏈在下一篇好好寫寫。