摘要:為了更好的理解,在閱讀此文之前建議先閱讀上一篇進擊之詞法作用域與作用域鏈什么是閉包閉包的含義就是閉合,包起來,簡單的來說,就是一個具有封閉功能與包裹功能的結構。在中函數構成閉包。
為了更好的理解,在閱讀此文之前建議先閱讀上一篇《進擊JavaScript之詞法作用域與作用域鏈》1.什么是閉包
閉包的含義就是閉合,包起來,簡單的來說,就是一個具有封閉功能與包裹功能的結構。所謂的閉包就是一個具有封閉的對外不公開的,包裹結構,或空間。
在JS中函數構成閉包。一般函數是一個代碼結構的封閉結構,即包裹的特性,同時根據作用域規則只允許函數訪問外部的數據,外部無法訪問函數內部的數據,即封閉的對外不公開的特性,因此說函數可以構成閉包。
概括:閉包就是一個具有封閉與包裹功能的結構。函數可以構成閉包。函數內部定義的數據函數外部無法訪問,即函數具有封閉性;函數可以封裝代碼即具有包裹性,所以函數可以構成閉包。2.閉包有什么用(解決什么問題)?
閉包不允許外部訪問
要解決的問題就是間接訪問該數據
函數就可以構成閉包,要解決的問題就是如何訪問到函數內部的數據
function foo () { var num = 123; return num; } var res = foo(); console.log( res ); // =>123
這里的確是訪問到函數中的數據了。但是該數據不能第二次訪問,因此第二次訪問的時候又要調用一次foo,表示又有一個新的num = 123出來了。
在函數內的數據,不能直接在函數外部訪問,那么在函數內如果定義一個函數,那么在這個函數內部中是可以直接訪問的
function foo() { var num = Math.random(); function func() { return mun; } return func; } var f = foo(); // f 可以直接訪問這個 num var res1 = f(); var res2 = f();
我們使用前面學習的繪制作用域鏈結構圖的方法來繪制閉包的作用域鏈結構圖,如下:
3.閉包使用舉例如何獲得超過一個數據
function foo () { var num1 = Math.random(); var num2 = Math.random(); return { num1: function () { return num1; }, num2: function () { return num2; } } }
如何完成讀取一個數據和修改這個數據
function foo () { var num = Math.random(); return { get_num : function () { return num; }, set_num: function( value ) { return num = value; } } }4.基本的閉包結構
一般閉包的問題就是要想辦法簡潔的獲取函數內的數據使用權,那么我們就可以總結出一個基本的使用模型。
寫一個函數,函數內部定義一個新函數,返回新函數,用新函數獲得函數內的數據
寫一個函數,函數內部定義個一個對象,對象中綁定多個函數(方法),返回對象,利用對象的方法訪問函數內的數據
5.閉包的基本用法閉包是為了實現具有私有訪問空間的函數的
帶有私有訪問數據的對象
function Person() { this.name = "張三"; // setName( "" ) }
所有的私有數據,就是說只有函數內部可以訪問的數據,或對象內部的方法可以訪問的數據
最簡單的實現:
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() );
帶有私有數據的函數
var func = function () {} function func () {} var foo = (function () { // 私有數據 return function () { // 可以使用私有的數據 ... }; });6.閉包基本模型
對象模型
function foo () { // 私有數據 return { method : function(){ // 操作私有數據 } } }
函數模型
function foo(){ // 私有數據 return function(){ // 可以操作私有數據 } }7.沙箱模式(閉包應用的一個典范) 7.1 沙箱的概念
沙盤與盒子,就可以在一個笑笑的空間內模擬顯示世界,特點是執行效果與現實世界一模一樣,但是在沙箱中模擬與現實無關.
7.2 沙箱模式沙箱模式就是一個自調用函數,代碼寫到函數中一樣會執行,但是不會與外界有任何的影響
例如,在jQuery中
(function () { var jQuery = function () { // 所有的算法 } // .... // .... jQuery.each = function () {} window.jQuery = window.$ = jQuery; })(); $.each( ... )8.帶有緩存功能的函數
以 Fibonacci 數列為例,改進傳統計算斐波那契數列方法
我們來回顧一下傳統遞歸方式求斐波那契數列方法,我們定義一個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次,性能太低了
性能低的原因是 重復計算。如果每次將計算的結果存起來
那么每次需要的時候先看看有沒有存儲過該數據,如果有,直接拿來用。
如果沒有再遞歸,但是計算的結果需要再次存儲起來,以便下次使用
改進版:
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.閉包的性能問題函數執行需要內存,那么函數中定義的變量,會在函數執行結束后自動回收,凡是因為閉包結構的,被引出的數據,如果還有變量引用這些數據的話,那么這些數據就不會被回收。
因此在使用閉包的時候如果不適用某學數據了,一定要賦值一個null
var f = (function () { var num = 123; return function () { return num; }; })(); // f 引用著函數,函數引用著變量num // 因此在不適用該數據的時候,最好寫上 f = null;
推薦閱讀
進擊JavaScript之(一)詞法作用域與作用域鏈
進擊JavaScript之(二)詞法作用域與作用域鏈
進擊JavaScript之(四)原型與原型鏈
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/80183.html
摘要:如下代碼輸出的結果是代碼執行分為兩個大步預解析的過程代碼的執行過程預解析與變量聲明提升程序在執行過程中,會先將代碼讀取到內存中檢查,會將所有的聲明在此進行標記,所謂的標記就是讓解析器知道有這個名字,后面在使用名字的時候不會出現未定義的錯誤。 showImg(https://segmentfault.com/img/remote/1460000012922850); 如下代碼輸出的結果是...
摘要:一作用域域表示的就是范圍,即作用域,就是一個名字在什么地方可以使用,什么時候不能使用。概括的說作用域就是一套設計良好的規則來存儲變量,并且之后可以方便地找到這些變量。 一、作用域 域表示的就是范圍,即作用域,就是一個名字在什么地方可以使用,什么時候不能使用。想了解更多關于作用域的問題推薦閱讀《你不知道的JavaScript上卷》第一章(或第一部分),從編譯原理的角度說明什么是作用域。概...
摘要:每一個由構造函數創建的對象都會默認的連接到該神秘對象上。在構造方法中也具有類似的功能,因此也稱其為類實例與對象實例一般是指某一個構造函數創建出來的對象,我們稱為構造函數的實例實例就是對象。表示該原型是與什么構造函數聯系起來的。 本文您將看到以下內容: 傳統構造函數的問題 一些相關概念 認識原型 構造、原型、實例三角結構圖 對象的原型鏈 函數的構造函數Function 一句話說明什么...
摘要:匿名函數是不能單獨寫的,所以就提不上立即執行了。六立即執行函數在閉包中的應用立即執行函數能配合閉包保存狀態。來看下上節內容中閉包的例子現在,我們來利用立即執行函數來簡化它第一個匿名函數執行完畢后,返回了第二個匿名函數。 前面的閉包中,提到與閉包相似的立即執行函數,感覺兩者還是比較容易弄混吧,嚴格來說(因為犀牛書和高程對閉包的定義不同),立即執行函數并不屬于閉包,它不滿足閉包的三個條件。...
摘要:此時產生了閉包。導致,函數的活動對象沒有被銷毀。是不是跟你想的不一樣其實,這個例子重點就在函數上,這個函數的第一個參數接受一個函數作為回調函數,這個回調函數并不會立即執行,它會在當前代碼執行完,并在給定的時間后執行。 上一節說了執行上下文,這節咱們就乘勝追擊來搞搞閉包!頭疼的東西讓你不再頭疼! 一、函數也是引用類型的。 function f(){ console.log(not cha...
閱讀 1140·2021-10-27 14:13
閱讀 2645·2021-10-09 09:54
閱讀 914·2021-09-30 09:46
閱讀 2432·2021-07-30 15:30
閱讀 2177·2019-08-30 15:55
閱讀 3419·2019-08-30 15:54
閱讀 2858·2019-08-29 14:14
閱讀 2780·2019-08-29 13:12