1. 程式人生 > >JavaScript學習筆記——閉包—day three

JavaScript學習筆記——閉包—day three

目錄

什麼是閉包

兩個經典邏輯案例

閉包的缺點

閉包的作用

1.實現公有變數

2.可以做快取(儲存結構)

3.可以實現封裝,屬性私有化

4.模組化開發,防止汙染全域性變數


什麼是閉包

當內部函式被儲存到外部時,將會生成閉包,生成閉包後,內部函式依舊可以訪問其所在的外部函式的變數。

兩個經典邏輯案例

例一

      function test() {
            var a = [];
            for (var i = 0; i < 10; i++) {
                a[i] = function () {
                    document.write(i + " ");
                }
            }
            return a;
        }
        var myArr = test();
        for(var j=0;j<10;j++)
        {
            myArr[j]();
        }

執行結果:10 10 10 10 10 10 10 10 10 10

10個10,經過for迴圈後 i=10,而return a 只是返回了函式內容(document.write(i + " ");)這裡的 i 就一直是10。

例二

這也是閉包的解決和防範方法:將 i(或者需要的變數等,但凡牽涉到索引的問題,一定要注意)變現。

       function test(){
            var arr=[];
            for(i=0;i<10;i++)
            {
                (function(j){
                   arr[j]=function(){
                    document.write(j+" ");
                   }
                }(i))
            }
           return arr;
        }
        var myArr=test();
        for(j=0;j<10;j++)
        {
            myArr[j]();
        }

執行結果:0 1 2 3 4 5 6 7 8 9

閉包的缺點

閉包會導致原有作用域鏈不釋放,造成記憶體洩漏(被佔用了,剩下的記憶體不是理論上應該多大的記憶體,並不是字面意思的洩漏)

閉包的作用

1.實現公有變數

如:函式累加器

 function a(){
            var num=100;
            function b(){
                num++;
            console.log(num);
            }
            return b;
        }
        var add=a();
        add();
        add();
        add();

2.可以做快取(儲存結構)

例1

        function test() {
            var num = 100;

            function a() {
                num++;
                console.log(num);
            }
            // a defined   a.[[scope]]    0:testAo
            //                            1:GO
            function b() {
                num--;
                console.log(num);
            }
            // a defined   a.[[scope]]    0:testAo
            //                             1:GO
            return [a, b];
        }
        var myArr = test();
        myArr[0]();
        // 代表a
        //  a doing   a.[[scope]]    0:aAO
        //                           1:testAo(函式結束,AO依舊保留)
        //                           2:GO
        myArr[1]();
        // 代表b
        //  b doing   b.[[scope]]    0:bAO
        //                           1:testAo(上一步更改過後的testAO)
        //                           2:GO

執行結果:101  100   兩個並列的函式使用的是同一個num,即一個testAO。

例二

       function eater() {
            var food = "";
            var obj = {
                eat: function () {
                    console.log("i am eating " + food);
                    food = "";
                },
                push: function (myFood) {
                    food = myFood;
                }
            }
            return obj;
        }
        var eaters = eater();
        eaters.push('banana');
        eaters.eat();

結果列印:i am eating banana  。這裡面的food就相當於一個儲存結構。物件裡面包含兩個函式,返回物件相當於返回兩個函式。兩個函式改變的始終都是同一個變數。

多個函式閉包,公用同一個變數。這種方式相當於快取。

3.可以實現封裝,屬性私有化

如:

        function Wang(name,old){
            var money=10000;
            this.name=name;
            this.old=old;
            this.save=function(){
                money++;
                console.log(money);
            }
        }
        var wang=new Wang('haha',46);

這裡的money就相當於一個私有屬性,不能直接訪問。

4.模組化開發,防止汙染全域性變數

名稱空間問題

管理變數,即使兩個函式中的變數名、函式名相同也不互相影響。開發的一個功能,以後會複用,就把它儲存到一個閉包裡面。

        var name = '123';
        var init=(function(){
            var name='456';
            function callName(){
                console.log(name);
            }
            return function(){
                callName();
            }
        }())
        var initWang=(function(){
            var name='789';
            function callName(){
                console.log(name);
            }
            return function(){
                callName();
            }
        }())