做用域鏈、閉包以及this的使用

執行環境與做用域:前端

每一個執行環境都有與之相關聯的變量對象,若是這個環境是函數,則將其活動對象(activation object)做爲變量對象環境中定義的全部變量和函數都保存在這個變量中,活動對象在最開始只包含一個arguments對象。數組

js的執行順序是根據函數的調用來決定的,當一個函數被調用時,該函數環境的變量對象就被壓入一個環境棧中。而在函數執行以後,棧將該函數的變量對象彈出,把控制權交給以前的執行環境變量對象。閉包

 

做用域污染:函數

只要函數內定義了一個局部變量,函數在解析時都會將這個變量「提早聲明」this

var scope = "global"; function fn(){ console.log(scope);//result:undefined
         var scope = "local"; console.log(scope);//result:local;
 } fn();

 

在js中能夠隨時定義全局變量,可是全局變量會削弱程序的靈活性,增大了模塊之間的耦合性。spa

在多人協做時,若是定義過多的全局變量,有可能形成全局變量的衝突,也就是全局變量的污染,有兩種解決方法:code

(1)定義全局變量命名空間xml

只建立一個全局變量,並定義該變量爲當前容器,把其餘全局變量寫到該命名空間下。對象

var myInfo={ name:'chengxi', like:'football', likeDo:function(){ alert(this.like); } }

(2)利用匿名函數將腳本包裹起來blog

(function(){ var exp={}; var name='aa'; exp.method=function(){ return name; }; window.ex=exp; })(); console.log(ex.method());//aa

 

做用域:

在js中做用域分爲全局做用域和函數做用域。 

 

做用域鏈:

當代碼在一個環境中執行時,會建立一個做用域鏈,其用途是保證對執行環境有權訪問的全部變量和函數的有序訪問。

好比查找一個變量,首先在當前做用域中查找,若是沒有,就會向上級做用域去查,直到查到全局做用域,這麼一個查找的過程造成的鏈條就叫作做用域鏈。

  做用域鏈的前端,始終都是當前執行的代碼所在環境的變量對象,若是這個環境是函數,則將其活動對象做爲變量對象,活動對象在最開始時只包含一個變量,即arguments對象。做用域鏈的下一變量對象來自於包含(外部)環境,全局執行環境的變量對象始終都是做用域鏈中的最後一個對象。

 
 
<script> function outer(){ var scope = "outer"; function inner(){ return scope; } return inner; } var fn = outer(); fn(); </script>
 

通常來講,當某個環境中的全部代碼執行完畢後,該環境被銷燬(彈出環境棧),保存在其中的全部變量和函數也隨之銷燬(全局執行環境變量直到應用程序退出,如網頁關閉纔會被銷燬)

 


可是像上面那種有內部函數的又有所不一樣,當outer()函數執行結束,執行環境被銷燬,可是其關聯的活動對象並無隨之銷燬,而是一直存在於內存中,由於該活動對象被其內部函數的做用域鏈所引用。

像上面這種內部函數的做用域鏈仍然保持着對父函數活動對象的引用,就是閉包(closure)

閉包有兩個做用:
第一個就是能夠讀取自身函數外部的變量(沿着做用域鏈尋找)
第二個就是讓這些外部變量始終保存在內存中 

//閉包 function outer(){ var result = new Array(); for(var i = 0; i < 2; i++){ result[i] = function(num){ return function(){ return num; } }(i) } return result; } var fn = outer(); console.log(fn[0]());//result:0
console.log(fn[1]());//result:1

   若是沒使用以上方式,i是貫穿整個做用於的,並非給每一個result分配一個i,因此用當即執行函數建立一個獨立的做用域便可。

 

  咱們沒有直接把閉包賦值給數組,而是定義了一個匿名函數,並將將當即執行該匿名函數的結果賦值給數組。這裏的匿名函數有一個參數num,也就是最終函數要返回的值。在調用每一個匿名函數時,傳入變量i的值,因爲函數參數是按值傳遞的,因此會將變量i的值賦值給參數num,而這個匿名函數內部,又建立並返回一個訪問num的閉包,這樣數組中的每一個函數都有本身num變量的一個副本,所以就能夠返回各自不一樣的值了。

相關文章
相關標籤/搜索