萬盛學電腦網

 萬盛學電腦網 >> 腳本專題 >> javascript >> 基於javascript 閉包基礎分享

基於javascript 閉包基礎分享

如果對作用域,函數為獨立的對象這樣的基本概念理解較好的話,理解閉包的概念並在實際的編程實踐中應用則頗有水到渠成之感。

在DOM的事件處理方面,大多數程序員甚至自己已經在使用閉包了而不自知,在這種情況下,對於浏覽器中內嵌的JavaScript引擎的bug可能造成內存洩漏這一問題姑且不論,就是程序員自己調試也常常會一頭霧水。
用 簡單的語句來描述JavaScript中的閉包的概念:由於JavaScript中,函數是對象,對象是屬性的集合,而屬性的值又可以是對象,則在函數內 定義函數成為理所當然,如果在函數func內部聲明函數inner,然後在函數外部調用inner,這個過程即產生了一個閉包。  
閉包的特性:
我們先來看一個例子,如果不了解JavaScript的特性,很難找到原因:

復制代碼 代碼如下:
var outter = [];
        function clouseTest() {
            var array = ["one", "two", "three", "four"];
            for (var i = 0; i < array.length; i++) {
                var x = {};
                x.no = i;
                x.text = array[i];
                x.invoke = function () {
                    print(i);
                }
                outter.push(x);
            }
        }
        //調用這個函數
        clouseTest();
        print(outter[0].invoke());
        print(outter[1].invoke());
        print(outter[2].invoke());
        print(outter[3].invoke());


運行的結果如何呢?很多初學者可能會得出這樣的答案:
0
1
2
3
然而,運行這個程序,得到的結果為:
4
4
4
4
其 實,在每次迭代的時候,這樣的語句x.invoke = function(){print(i);}並沒有被執行,只是構建了一個函數體為”print(i);”的函數對象,如此而已。而當i=4時,迭代停 止,外部函數返回,當再去調用outter[0].invoke()時,i的值依舊為4,因此outter數組中的每一個元素的invoke都返回i的 值:4。如何解決這一問題呢?我們可以聲明一個匿名函數,並立即執行它:

復制代碼 代碼如下:
var outter = [];
        function clouseTest2() {
            var array = ["one", "two", "three", "four"];
            for (var i = 0; i < array.length; i++) {
                var x = {};
                x.no = i;
                x.text = array[i];
                x.invoke = function (no) {
                    return function () {
                        print(no);
                    }
                }(i);
                outter.push(x);
            }
        }
        clouseTest2();
    </script>


這個例子中,我們為x.invoke賦值的時候,先運行一個可以返回一個函數的函數,然後立即執行之,這樣,x.invoke的每一次迭代器時相當與執行這樣的語句:

復制代碼 代碼如下:
//x == 0
x.invoke = function(){print(0);}
//x == 1
x.invoke = function(){print(1);}
//x == 2
x.invoke = function(){print(2);}
//x == 3
x.invoke = function(){print(3);}


這樣就可以得到正確結果了。閉包允許你引用存在於外部函數中的變量。然而,它並不是使用該變量創建時的值,相反,它使用外部函數中該變量最後的值。
閉包的用途:
現在,閉包的概念已經清晰了,我們來看看閉包的用途。事實上,通過使用閉包,我們可以做很多事情。比如模擬面向對象的代碼風格;更優雅,更簡潔的表達出代碼;在某些方面提升代碼的執行效率。

緩存:
再來看一個例子,設想我們有一個處理過程很耗時的函數對象,每次調用都會花費很長時間,那麼我們就需要將計算出來的值存儲起來,當調用這個函數的時候,首先在緩存中查找,如果找不到,則進行計算,然後更新緩存並返回值,如果找到了,直接返回查找到的值即可。
閉包正是可以做到這一點,因為它不會釋放外部的引用,從而函數內部的值可以得以保留。

復制代碼 代碼如下:
var CachedSearchBox = (function () {
            var cache = {},
               count = [];
            return {
                attachSearchBox: function (dsid) {
                    if (dsid in cache) {//如果結果在緩存中
                        return cache[dsid];//直接返回緩存中的對象
                    }
                    var fsb = document.getElementById(dsid);//新建
                    cache[dsid] = fsb;//更新緩存
                    if (count.length > 100) {//保正緩存的大小<=100
                        delete cache[count.shift()];
                    }
                    return fsb;
                },
            
copyright © 萬盛學電腦網 all rights reserved