JS閉包知識分享

很多同學在面試的時候都會被問到閉包是什麼?舉例說明下閉包的運用?

今天我就跟大家分享下什麼是閉包,閉包的具體使用

閉包(closure)是javascript的一大難點,也是它的特色。很多高級應用都要依靠閉包來實現。

要理解閉包,首先要理解javascript的全局變量和局部變量。

javascript語言的特別之處就在於:函數內部可以直接讀取全局變量,但是在函數外部無法讀取函數內部的局部變量。

function f1(){

var a=10;

function f2(){

alert(a); // 10

}

}

如何從外部讀取函數內部的局部變量?

我們有時候需要獲取到函數內部的局部變量,正常情況下,這是辦不到的!只有通過變通的方法才能實現。那就是在函數內部,再定義一個函數。

閉包的概念

上面代碼中的f2函數,就是閉包。

各種專業文獻的閉包定義都非常抽象,我的理解是: 閉包就是能夠讀取其他函數內部變量的函數。

由於在javascript中,只有函數內部的子函數才能讀取局部變量,所以說,閉包可以簡單理解成“定義在一個函數內部的函數“。

所以,在本質上,閉包是將函數內部和函數外部連接起來的橋樑。

閉包的用途

閉包可以用在許多地方。它的最大用處有兩個,一個是前面提到的可以讀取函數內部的變量,另一個就是讓這些變量的值始終保持在內存中,不會在f1調用後被自動清除。

為什麼會這樣呢?原因就在於f1是f2的父函數,而f2被賦給了一個全局變量,這導致f2始終在內存中,而f2的存在依賴於f1,因此f1也始終在內存中,不會在調用結束後,被垃圾回收機制(garbage collection)回收。

在我們平時的代碼中經常會用到閉包,比如在構造函數中

function a(){

var n = 0;

this.add = function () {

n++;

console.log(n);

};

}

var c = new a();

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

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

//另一種寫法

function a(){

this.n = 0,

this.add = function () {

this.n++;

console.log(this.n);

};

}

var c = new a();

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

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

常見閉包的寫法

function a(){ var n = 0; function add(){ n++; console.log(n); } return add; } var a1 = a(); //注意,函數名只是一個標識(指向函數的指針),而()才是執行函數; a1(); //控制檯輸出1 a1(); //控制檯輸出2 另一種調用方法 function a(){ var n = 0; function add(){ n++; console.log(n); } return add; } a()();

//定義函數並立即調用

var a = (function() { var n = 0; return function() { n++; console.log(n); }; }()); a()

閉包的實際應用

使用閉包,我們可以做很多事情。比如模擬面向對象的代碼風格;更優雅,更簡潔的表達出代碼;在某些方面提升代碼的執行效率。

封裝

var person = function(){ //變量作用域為函數內部,外部無法訪問 var name = "張三"; return { getName : function(){ return name; }, setName : function(newName){ name = newName; } } }(); Console.log(person.name); 通過person.name是無法獲取到name的值,如果要獲取到name的值可以通過 Console.log(person.getName()); //直接獲取到 張三 person.setName("李四"); //重新設置新的名字 print(person.getName()); //獲取 李四 繼承 function Person(){ var name = "張三"; return { getName : function(){ return name; }, setName : function(newName){ name = newName; } } }; var BlackPeople = function(){}; //黑人繼承自Person BlackPeople.prototype = new Person(); var p = new BlackPeople(); p.setName("Tom"); console.log(p.getName()); // Tom

總結:閉包就是一個函數引用另外一個函數的變量,因為變量被引用著所以不會被回收,因此可以用來封裝一個私有變量。這是優點也是缺點,不必要的閉包只會徒增內存消耗!