JS閉包知識分享

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
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

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


分享到:


相關文章: