閉包和當即執行函數

閉包就是可以讀取其餘函數內部變量的函數。html

function a(){
    var n = 0;
    function inc() {
        n++;
        console.log(n);
    }
    inc();  
    inc(); 
}
a(); //控制檯輸出1,再輸出2

 

 

function a(){閉包

    var n = 0;函數

    this.inc = function () {性能

        n++;this

        console.log(n);spa

    };htm

}對象

var c = new a();內存

c.inc();    //控制檯輸出1ci

c.inc();    //控制檯輸出2

 

 

function a(){
    var n = 0;
    function inc(){
       n++; 
       console.log(n);
    }
    return inc;
}
var c = a();
c();    //控制檯輸出1
c();    //控制檯輸出2
var c1 = a();
c1();    //控制檯輸出1
c1();    //控制檯輸出2

 

閉包陷阱:

function createFunctions(){
    var result = new Array();
    for (var i=0; i < 10; i++){
        result[i] = function(){
            return i;
        };
    }
    return result;
}
var funcs = createFunctions();
for (var i=0; i < funcs.length; i++){
    console.log(funcs[i]());
}

乍一看,覺得輸出 0~9 ,萬萬沒想到輸出10個10? 

 

解決閉包問題:

function createFunctions() {

    var result = new Array();

    for (var i = 0; i < 10; i++) {

        (function(i) {//添加一個當即執行的函數

            result[i] = function() {

                return i;

            };

        })(i);

    }

    return result;

}

var funcs = createFunctions();

for (var i = 0; i < funcs.length; i++) {

    console.log(funcs[i]());

}

 

var result = new Array(), i;
result[0] = function(){ return i; }; //沒執行函數,函數內部不變,不能將函數內的i替換!
result[1] = function(){ return i; }; //沒執行函數,函數內部不變,不能將函數內的i替換!
...
result[9] = function(){ return i; }; //沒執行函數,函數內部不變,不能將函數內的i替換!
i = 10;
funcs = result;
result = null;
 
console.log(i); // funcs[0]()就是執行 return i 語句,就是返回10
console.log(i); // funcs[1]()就是執行 return i 語句,就是返回10
...
console.log(i); // funcs[9]()就是執行 return i 語句,就是返回10

 

 

 

 function f1(){

    n=999;

    function f2(){

      return (n); // 999

    };

return f2;

};

f1()();

//控制檯輸出999

 

當即執行函數:

 (function f1(){

    n=999;

    function f2(){

      return (n); // 999

    };return f2;

  })();

//控制檯輸出

function f2(){

   return (n); // 999

 }

 

 

 (function f1(){

    n=999;

    function f2(){

      return (n); // 999

    };return f2;

  })()();

//控制檯輸出

999

 

 

 (function f1(){

    n=999;

    function f2(){

      return (n); // 999

    };return f2;

  }())();

//控制檯輸出

999

 

 

function f1(){

    var n=999;

    nAdd=function(){n+=1}

    function f2(){

      alert(n);

    }

    return f2;

  }

  var result=f1();

  result(); // 999

  nAdd();

  result(); // 1000

在這段代碼中,result實際上就是閉包f2函數。它一共運行了兩次,第一次的值是999,第二次的值是1000。這證實了,函數f1中的局部變量n一直保存在內存中,並無在f1調用後被自動清除。

爲何會這樣呢?緣由就在於f1是f2的父函數,而f2被賦給了一個全局變量,這致使f2始終在內存中,而f2的存在依賴於f1,所以f1也始終在內存中,不會在調用結束後,被垃圾回收機制(garbage collection)回收。

這段代碼中另外一個值得注意的地方,就是「nAdd=function(){n+=1}」這一行,首先在nAdd前面沒有使用var關鍵字,所以 nAdd是一個全局變量,而不是局部變量。其次,nAdd的值是一個匿名函數(anonymous function),而這個匿名函數自己也是一個閉包,因此nAdd至關因而一個setter,能夠在函數外部對函數內部的局部變量進行操做。

 

使用閉包的注意點

  1)因爲閉包會使得函數中的變量都被保存在內存中,內存消耗很大,因此不能濫用閉包,不然會形成網頁的性能問題,在IE中可能致使內存泄露。解決方法是,在退出函數以前,將不使用的局部變量所有刪除

  2)閉包會在父函數外部,改變父函數內部變量的值。因此,若是你把父函數看成對象(object)使用,把閉包看成它的公用方法(Public Method),把內部變量看成它的私有屬性(private value),這時必定要當心,不要隨便改變父函數內部變量的值。

 

內存泄漏也稱做"存儲滲漏",用動態存儲分配函數動態開闢的空間,在使用完畢後未釋放,結果致使一直佔據該內存單元。直到程序結束。(其實說白了就是該內存空間使用完畢以後未回收)即所謂內存泄漏。

 

var name = "The Window";  

var object = {    

    name: "My Object",

        getNameFunc: function() {      

        return function() {        

            return this.name;     

        };    

    }

};

alert(object.getNameFunc()()); //The Window

//控制檯輸出The Window

 

function outerFun() {

    var a = 0;

    console.log(a);

}

var a = 4;

outerFun();

console.log(a);

//控制檯輸出0,4

 

做用域鏈

function outerFun() {

    //沒有var

    a = 0;

    alert(a);

}

var a = 4;

outerFun();

alert(a);

結果爲 0, 0 真是奇怪, 爲何呢 ?

 

    做用域鏈是描述一種路徑的術語, 沿着該路徑能夠肯定變量的值。 當執行a = 0時, 由於沒有使用var關鍵字, 所以賦值操做會沿着做用域鏈到var a = 4;

並改變其值。

相關文章
相關標籤/搜索