讀書筆記——javascript閉包

    前幾天有人問關於javascript的閉包的問題,這裏,首先引用一下《JavaScript權威指南》第6版中第八章第6節的內容,裏面講得非常詳細:

   和其他大多數現代編程語言一樣,JavaScript也採用詞法作用域(lexical scoping),也就是說,函數的執行依賴於變量作用域,這個作用域是在函數定義時決定的,而不是函數調用時決定的。爲了實現這種詞法作用域,JavaScript函數對象的內部狀態不僅包含函數的代碼邏輯,還必須引用當前的作用域鏈。函數對象可以通過作用域鏈相互關聯起來,函數體內部的變量都可以保存在函數作用域內,這種特性在計算機科學文獻中稱爲“閉包”(這個術語非常古老,是指函數變量可以被隱藏於作用域鏈之內,因此看起來是函數將變量“包裹”了起來)。

    從技術角度講,所有的JavaScript函數都是閉包:它們都是對象,它們都關聯到作用域鏈。定義大多數函數時的作用域鏈在調用函數時依然有效,但這並不影響閉包。當調用函數時閉包所指向的作用域鏈和定義函數時的作用域鏈不是同一個作用域鏈時,事情就變得非常微妙。當一個函數嵌套了另外一個函數,外部函數將嵌套的函數對象作爲返回值返回的時候往往會發生這種事情。有很多強大的編程技術都利用到了這類嵌套的函數閉包,以至於這種編程模式在JavaScript中非常常見。當你第一次碰到閉包時可能會覺得非常讓人費解,一旦你理解掌握了閉包之後,就能非常自如地使用它了,瞭解這一點至關重要。

    理解閉包首先要了解嵌套函數的詞法作用域規則。看一下這段代碼:

***********************************************************************************

var scope = "global scope";       //全局變量    
function checkscope(){        
    var scope = "local scope";    //局部變量        
    function f(){return scope;}   //在作用域中返回這個值        
    return f();    
}    
console.log(checkscope() );       //==>"local scope"


***********************************************************************************

checkscope()函數聲明瞭一個局部變量,並定義了一個函數f(),函數f()返回了這個變量的值,最後將函數f()的執行結果返回。

    現在,我們把以上代碼略作改變:

***********************************************************************************

 var scope = "global scope";            //全局變量
 function checkscope(){
     var scope = "local scope";         //局部變量        
     function f(){return scope;}        //在作用域中返回這個值      
     return f;    
}    
console.log(checkscope()()) ;           //==>"local scope"


***********************************************************************************

在這段代碼中,我們將函數內的一對圓括號移動到checkscope()之後。checkscope()現在僅僅返回函數內嵌套的一個函數對象,而不是直接返回結果。在定義函數的作用域外面,調用這個嵌套的函數(包括最後一行代碼的最後一對圓括號)會發生什麼事情呢?

       回想一下詞法作用域的基本規則:JavaScript函數的執行用到了作用域鏈,這個作用域鏈是函數定義的時候創建的。嵌套在何時何地執行函數f(),這種綁定在執行f()時依然有效。因此最後一行代碼返回“local scope”,而不是global scope。簡而言之,閉包的這個特性強大到讓人吃驚:它們可以捕捉到局部變量和參數),並一直保存下來,看起來像這些變量綁定到了在其中定義它們的外部函數。



 待續





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章