JavaScript進階(三)閉包原理與用法詳解
本文實例講述了JavaScript閉包原理與用法。分享給大家供大家參考,具體如下:
為了更好的理解,在閱讀此文之前建議先閱讀上一篇《JavaScript詞法作用域與作用域鏈》
1.什么是閉包
閉包的含義就是閉合,包起來,簡單的來說,就是一個具有封閉功能與包裹功能的結構。所謂的閉包就是一個具有封閉的對外不公開的,包裹結構,或空間。
在JS中函數(shù)構成閉包。一般函數(shù)是一個代碼結構的封閉結構,即包裹的特性,同時根據(jù)作用域規(guī)則只允許函數(shù)訪問外部的數(shù)據(jù),外部無法訪問函數(shù)內部的數(shù)據(jù),即封閉的對外不公開的特性,因此說函數(shù)可以構成閉包。
概括:閉包就是一個具有封閉與包裹功能的結構。函數(shù)可以構成閉包。函數(shù)內部定義的數(shù)據(jù)函數(shù)外部無法訪問,即函數(shù)具有封閉性;函數(shù)可以封裝代碼即具有包裹性,所以函數(shù)可以構成閉包。
2.閉包有什么用(解決什么問題)?
- 閉包不允許外部訪問
- 要解決的問題就是間接訪問該數(shù)據(jù)
函數(shù)就可以構成閉包,要解決的問題就是如何訪問到函數(shù)內部的數(shù)據(jù)
function foo () {
var num = 123;
return num;
}
var res = foo();
console.log( res ); // =>123
這里的確是訪問到函數(shù)中的數(shù)據(jù)了。但是該數(shù)據(jù)不能第二次訪問,因此第二次訪問的時候又要調用一次foo,表示又有一個新的num = 123出來了。
在函數(shù)內的數(shù)據(jù),不能直接在函數(shù)外部訪問,那么在函數(shù)內如果定義一個函數(shù),那么在這個函數(shù)內部中是可以直接訪問的
function foo() {
var num = Math.random();
function func() {
return mun;
}
return func;
}
var f = foo();
// f 可以直接訪問這個 num
var res1 = f();
var res2 = f();
我們使用前面學習的繪制作用域鏈結構圖的方法來繪制閉包的作用域鏈結構圖,如下:

3.閉包使用舉例
如何獲得超過一個數(shù)據(jù)
function foo () {
var num1 = Math.random();
var num2 = Math.random();
return {
num1: function () {
return num1;
},
num2: function () {
return num2;
}
}
}
如何完成讀取一個數(shù)據(jù)和修改這個數(shù)據(jù)
function foo () {
var num = Math.random();
return {
get_num : function () {
return num;
},
set_num: function( value ) {
return num = value;
}
}
}
4.基本的閉包結構
一般閉包的問題就是要想辦法簡潔的獲取函數(shù)內的數(shù)據(jù)使用權,那么我們就可以總結出一個基本的使用模型。
- 寫一個函數(shù),函數(shù)內部定義一個新函數(shù),返回新函數(shù),用新函數(shù)獲得函數(shù)內的數(shù)據(jù)
- 寫一個函數(shù),函數(shù)內部定義個一個對象,對象中綁定多個函數(shù)(方法),返回對象,利用對象的方法訪問函數(shù)內的數(shù)據(jù)
5.閉包的基本用法
閉包是為了實現(xiàn)具有私有訪問空間的函數(shù)的
帶有私有訪問數(shù)據(jù)的對象
function Person() {
this.name = "張三";
// setName( '' )
}
所有的私有數(shù)據(jù),就是說只有函數(shù)內部可以訪問的數(shù)據(jù),或對象內部的方法可以訪問的數(shù)據(jù)
最簡單的實現(xiàn):
function createPerson() {
var __name__ = "";
return {
getName: function () {
return __name__;
},
setName: function( value ) {
// 如果不姓張就報錯
if ( value.charAt(0) === '張' ) {
__name__ = value;
} else {
throw new Error( '姓氏不對,不能取名' );
}
}
}
}
var p = createPerson();
p.set_Name( '張三豐' );
console.log( p.get_Name() );
p.set_Name( '張王富貴' );
console.log( p.get_Name() );
帶有私有數(shù)據(jù)的函數(shù)
var func = function () {}
function func () {}
var foo = (function () {
// 私有數(shù)據(jù)
return function () {
// 可以使用私有的數(shù)據(jù)
...
};
});
6.閉包基本模型
對象模型
function foo () {
// 私有數(shù)據(jù)
return {
method : function(){
// 操作私有數(shù)據(jù)
}
}
}
函數(shù)模型
function foo(){
// 私有數(shù)據(jù)
return function(){
// 可以操作私有數(shù)據(jù)
}
}
7.沙箱模式(閉包應用的一個典范)
7.1 沙箱的概念
沙盤與盒子,就可以在一個笑笑的空間內模擬顯示世界,特點是執(zhí)行效果與現(xiàn)實世界一模一樣,但是在沙箱中模擬與現(xiàn)實無關.
7.2 沙箱模式
沙箱模式就是一個自調用函數(shù),代碼寫到函數(shù)中一樣會執(zhí)行,但是不會與外界有任何的影響
例如,在jQuery中
(function () {
var jQuery = function () { // 所有的算法 }
// .... // .... jQuery.each = function () {}
window.jQuery = window.$ = jQuery;
})();
$.each( ... )
8.帶有緩存功能的函數(shù)
以 Fibonacci 數(shù)列為例,改進傳統(tǒng)計算斐波那契數(shù)列方法
我們來回顧一下傳統(tǒng)遞歸方式求斐波那契數(shù)列方法,我們定義一個count變量來查看遞歸了多少次:
var count = 0;
function fibo( n ){
count++;
if( n ==0 || n == 1 ) return 1;
return fibo( n - 1 ) + fibo( n - 2 );
}
fib1( 20 );
console.log( count1 );
// 5: 15
// 6: 25
// ...
// 20: 21891
當 n = 5 式,count = 15,當時當 n = 20 的時候,count就達到驚人的21891次,性能太低了
性能低的原因是 重復計算。如果每次將計算的結果存起來
- 那么每次需要的時候先看看有沒有存儲過該數(shù)據(jù),如果有,直接拿來用。
- 如果沒有再遞歸,但是計算的結果需要再次存儲起來,以便下次使用
改進版:
var data = [ 1, 1 ];
var count = 0;
function fibo( n ) {
count++;
var v = data[ n ];
if( v === undefined ){
v = fibo( n - 1 ) + fibo( n - 2 );
data[ n ] = v;
}
return v;
}
fibo( 100 );
console.log( count ); // 199
改進之后, n = 100的時候也才199次,大大提高了性能。
9.閉包的性能問題
函數(shù)執(zhí)行需要內存,那么函數(shù)中定義的變量,會在函數(shù)執(zhí)行結束后自動回收,凡是因為閉包結構的,被引出的數(shù)據(jù),如果還有變量引用這些數(shù)據(jù)的話,那么這些數(shù)據(jù)就不會被回收。
因此在使用閉包的時候如果不適用某學數(shù)據(jù)了,一定要賦值一個null
var f = (function () {
var num = 123;
return function () {
return num;
};
})();
// f 引用著函數(shù),函數(shù)引用著變量num
// 因此在不適用該數(shù)據(jù)的時候,最好寫上
f = null;
感興趣的朋友可以使用在線HTML/CSS/JavaScript代碼運行工具:http://tools.jb51.net/code/HtmlJsRun測試上述代碼運行效果。
更多關于JavaScript相關內容可查看本站專題:《JavaScript常用函數(shù)技巧匯總》、《javascript面向對象入門教程》、《JavaScript錯誤與調試技巧總結》、《JavaScript數(shù)據(jù)結構與算法技巧總結》及《JavaScript數(shù)學運算用法總結》
希望本文所述對大家JavaScript程序設計有所幫助。
相關文章
javascript實現(xiàn)通過表格繪制顏色填充矩形的方法
這篇文章主要介紹了javascript實現(xiàn)通過表格繪制顏色填充矩形的方法,涉及javascript操作表格與樣式的相關技巧,需要的朋友可以參考下2015-04-04
JavaScript實現(xiàn)指定數(shù)量的并發(fā)限制的示例代碼
這篇文章主要介紹了JavaScript實現(xiàn)指定數(shù)量的并發(fā)限制的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-03-03

