DIV CSS 佈局教程網

閉包(Closure)
編輯:JavaScript基礎知識     

閉包是JavaScript的一大難點,也是它的特色。利用閉包可以實現許多高級應用。今天我們就一起來討論一下有關閉包的問題。


一.閉包的概念

很多語言中都有閉包,概念也不盡相同。就JS閉包的概念也有好多種,下面一種我認為是比較好理解也比較精確的一種。

閉包是指有權訪問另一個函數作用域中的變量的函數。

這句話可以分為兩步來理解:
1)閉包是函數;
2)這個函數可以訪問另一個函數作用域中的變量。

等等,作用域又是什麼鬼。。。

第二點翻譯一下就是可以訪問另一個函數內部定義的變量。下面再解釋什麼是作用域。

示例代碼:

function outer() {
    var name = "Foolgry";
    
    function inner() {
        return name;
    }
}

從技術層面來說,上面的inner已經是一個閉包了。
1)它是一個函數;
2)它可以訪問outer內部定義的變量name
但是,大多數人習慣的閉包是下面這個樣子的:

示例代碼:

function outer() {
    var name = "Foolgry";
    
    function inner() {
        return name;
    }
    return inner;
}

var getName = outer(); 

getName(); // "Foolgry"

這個inner肯定是閉包,它不僅滿足上面的兩個條件,還具備一個特征:即使outer運行後被回收,它能夠保證name在內存中繼續存在。
每個人都有不同的理解,有的人認為只有第二個例子才算閉包,第一個例子不算。我的理解是都可以算做閉包。

閉包本身並不難理解,難得是它和作用域this等問題放在一起。
說起閉包,就不得不談一些基礎問題,比如:上面提到的作用域


二.作用域

JS中有兩種作用域,全局作用域和局部作用域。

示例代碼:

var name = "Bob",//全局作用域下定義的變量(全局變量)
    age = 99,
    sex = "female";
function object() {
    var name = "Foolgry"; //局部作用域下定義的變量(局部變量)
    
    alert(name); // "Foolgry"
    alert(age); // 99
    alert(sex); // undefined
    
    var sex = "male",
        job = "fe"
}
alert(name);  // "Foolgry"
alert(job); // error
  • object作用域中,name是局部變量,雖然全局環境中也定義了變量name,但是在局部作用域中,會優先訪問局部變量;
  • 如果訪問不到,才找全局變量,如age一樣;
  • sex為什麼是undefined呢?因為JS中有一種機制叫做變量提升。這東西會把上面幾句話變成這樣:

    var sex;
    alert(sex);
    sex = "male";
  • 訪問job發生錯誤,是因為一般情況下局部變量只能在其函數作用域內部訪問,這也是為什麼需要閉包了。


三.閉包應用

閉包的應用有很多,這裡只列舉其中兩種:

  • 模塊化代碼,減少全局變量的污染
  • 私有成員的存在

四.閉包需要注意的問題

1)由於閉包會使得函數中的變量都被保存在內存中,內存消耗很大,所以不能濫用閉包,否則會造成網頁的性能問題,在IE中可能導致內存洩露。解決方法是,在退出函數之前,將不使用的局部變量全部刪除。

2)閉包會在父函數外部,改變父函數內部變量的值。所以,如果你把父函數當作對象(object)使用,把閉包當作它的公用方法(Public Method),把內部變量當作它的私有屬性(private value),這時一定要小心,不要隨便改變父函數內部變量的值。


五.閉包經典例子

function fun(n,o) {
    console.log(o);
        return {
            fun:function(m) {
                return fun(m,n);
            }
        };
}
var a = fun(0); a.fun(1);  a.fun(2);  a.fun(3);  
var b = fun(0).fun(1).fun(2).fun(3);
var c = fun(0).fun(1);  c.fun(2);  c.fun(3);

問:三行a,b,c的輸出分別是什麼?

這個例子如果你能全部答對,那麼JS閉包就沒什麼問題了。

undefined,0,0,0
undefined,0,1,2
undefined,0,1,1

下一篇文章討論一下這題解法。

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved