閉包就是可以讀取其餘函數內部變量的函數。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++; } 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; 並改變其值。 |