上一節咱們說到做用域:是指變量能夠訪問的範圍,他規定了如何查找變量,以及肯定當前執行代碼對變量的訪問權限;也說到靜態做用域即詞法做用域,是在編譯階段決定變量的引用(由程序定義的位置決定,和代碼執行順序無關,用嵌套的方式解析)。javascript
1 var x=10; 2 function run(){ 3 var name='Joel'; 4 console.log(x+name);//10Joel 這裏作了隱適轉換 當有+時有一個爲string 那麼會當作字符拼接來處理 5 } 6 run();
如上代碼,在執行run函數時,在run做用域中有name變量,可是並無變量x,那麼爲何不會報錯,變量x又是怎麼訪問的呢?可能有些人理解是去父級函數做用域中尋找變量,其實這樣理解做用域存在歧義(若是理解爲是在調用函數的父級函數,那麼確定是錯的 以下代碼),上一節咱們說過javascript的做用域是靜態做用域,即應該關心代碼定義的位置而不是調用的位置 (詞法做用域);java
1 var x=10; 2 function fn(){ 3 console.log(x); 4 } 5 function show(f){ 6 var x=20; 7 (function(){ 8 f() 9 }()); 10 } 11 show(fn);//10 並非20
經過分析做用域的變量解析來理解做用域鏈函數
1 var a=10; 2 function run(){ 3 var name='Joel'; 4 function say(){ 5 var content='hello'; 6 console.log(content+name+','+a); 7 } 8 say(); 9 } 10 run();//helloJoel,10
經過上一篇咱們知道js做用域有全局做用域,函數做用域,因此上面代碼做用域以下:spa
全局做用域:存在變量a、run函數引用,固然還存在其餘函數、屬性(內置的就不討論了);3d
run函數做用域:存在變量 name 、say函數引用;指針
say函數做用域:存在變量content;code
當代碼執行到 console.log(content+name+','+a); 首先在say函數做用域中尋找變量content、name、a,若是找到則中止,沒有找到就到上一個做用域中尋找,以此類推一直到window 全局做用域,如變量a 在當前say 做用域中沒有,就到run做用域中尋找,還沒找到就到全局做用域中尋找,若是還找不到就報錯 is not defined,由於全局做用域是最外層做用域 ;對象
繼續看下面代碼,咱們在say函數中定義了變量name 以後,name值不在是run做用域中的值,由於在say做用域中找到了變量name 就不會繼續尋找了blog
1 <script> 2 var a=10; 3 function run(){ 4 var name='Joel'; 5 function say(){ 6 var content='hello',name=' Word'; 7 8 console.log(content+name+','+a); 9 } 10 say(); 11 } 12 run();//hello Word,10 13 </script>
這樣一步一步的尋找變量的過程咱們叫作標識符解析或者你能夠理解爲變量解析,那麼提供這個線路或者這樣尋找變量的機制咱們叫作做用域鏈;ip
咱們來總結一下這個過程:
第一步,在當前做用域查找變量,若是有則獲取並中止。若是沒有則繼續向上一個做用域尋找;
第二步,若是當前做用域是全局做用域,則說明變量未定義,結束;不然繼續;
第三步,(不是全局做用域,那就是函數做用域)繼續第一步;
那麼做用域鏈究竟是什麼呢?
其實做用域鏈本質是一個指向變量對象的指針鏈表,它只引用但不實際包含變量對象的值;
如上代碼做用域鏈結構相似這樣:
這篇只是引出做用域鏈,下一篇正式開始說執行環境,會涉及到變量對象、活動對象、做用域鏈等內容從而深刻做用域鏈的建立過程。
之因此要先寫執行環境,是由於完整的做用域鏈是在執行環境中構建的。