js中的閉包理解一

閉包是一個比較抽象的概念,尤爲是對js新手來講.書上的解釋實在是比較晦澀,對我來講也是同樣.html

  可是他也是js能力提高中沒法繞過的一環,幾乎每次面試必問的問題,由於在回答的時候.你的答案的深度,對術語的理解以及js內部解釋器的運做方式的描述,都是能夠看出你js實際水平的.即便你沒答對,也能讓考官對你的水平有個評估.那麼我先來講說我對js中的閉包的理解.程序員

  閉包是不少語言都具有的特性,在js中,閉包主要涉及到js的幾個其餘的特性:做用域鏈,垃圾(內存)回收機制,函數嵌套,等等.面試

  在理解閉包之前.最好能先理解一下做用域鏈的含義,簡單來講,做用域鏈就是函數在定義的時候建立的,用於尋找使用到的變量的值的一個索引,而他內部的規則是,把函數自身的本地變量放在最前面,把自身的父級函數中的變量放在其次,把再高一級函數中的變量放在更後面,以此類推直至全局對象爲止.當函數中須要查詢一個變量的值的時候,js解釋器會去做用域鏈去查找,從最前面的本地變量中先找,若是沒有找到對應的變量,則到下一級的鏈上找,一旦找到了變量,則再也不繼續.若是找到最後也沒找到須要的變量,則解釋器返回undefined.閉包

  瞭解了做用域鏈,咱們再來看看js的內存回收機制,通常來講,一個函數在執行開始的時候,會給其中定義的變量劃份內存空間保存,以備後面的語句所用,等到函數執行完畢返回了,這些變量就被認爲是無用的了.對應的內存空間也就被回收了.下次再執行此函數的時候,全部的變量又回到最初的狀態,從新賦值使用.可是若是這個函數內部又嵌套了另外一個函數,而這個函數是有可能在外部被調用到的.而且這個內部函數又使用了外部函數的某些變量的話.這種內存回收機制就會出現問題.若是在外部函數返回後,又直接調用了內部函數,那麼內部函數就沒法讀取到他所須要的外部函數中變量的值了.因此js解釋器在遇到函數定義的時候,會自動把函數和他可能使用的變量(包括本地變量和父級和祖先級函數的變量(自由變量))一塊兒保存起來.也就是構建一個閉包,這些變量將不會被內存回收器所回收,只有當內部的函數不可能被調用之後(例如被刪除了,或者沒有了指針),纔會銷燬這個閉包,而沒有任何一個閉包引用的變量纔會被下一次內存回收啓動時所回收.函數

也就是說,有了閉包,嵌套的函數結構才能夠運做,這也是符合咱們的預期的.而後,閉包還有一些特性,卻每每讓程序員以爲很難理解.spa

看看下面一段代碼.指針

var result=[];
function foo(){
    var i= 0;
    for (;i<3;i=i+1){
        result[i]=function(){
            alert(i)
        }
    }
};
foo();
result[0](); // 3
result[1](); // 3
result[2](); // 3

這段代碼中,程序員但願foo函數中的變量i被內部循環的函數使用,而且能分別得到他們的索引,而實際上,只能得到該變量最後保留的值,也就是說.閉包中所記錄的自由變量,只是對這個變量的一個引用,而非變量的值,當這個變量被改變了,閉包裏獲取到的變量值,也會被改變.code

解決的方法之一,是讓內部函數在循環建立的時候當即執行,而且捕捉當前的索引值,而後記錄在本身的一個本地變量裏.而後利用返回函數的方法,重寫內部函數,讓下一次調用的時候,返回本地變量的值,改進後的代碼:htm

var result=[];
function foo(){
    var i= 0;
    for (;i<3;i=i+1){
        result[i]=(function(j){
            return function(){
                alert(j);
            };
        })(i);
    }
};
foo();
result[0](); // 0
result[1](); // 1
result[2](); // 2

在這裏我再解釋一下.這裏用到了另外2個技術,當即調用的匿名函數和返回函數.也是初學者比較難以理解的部分.對象

轉自

:http://www.cnblogs.com/mzwr1982/archive/2012/05/20/2509295.html

相關文章
相關標籤/搜索