成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

進(jìn)擊JavaScript之(三)玩轉(zhuǎn)閉包

cyixlq / 1594人閱讀

摘要:為了更好的理解,在閱讀此文之前建議先閱讀上一篇進(jìn)擊之詞法作用域與作用域鏈?zhǔn)裁词情]包閉包的含義就是閉合,包起來,簡單的來說,就是一個(gè)具有封閉功能與包裹功能的結(jié)構(gòu)。在中函數(shù)構(gòu)成閉包。

為了更好的理解,在閱讀此文之前建議先閱讀上一篇《進(jìn)擊JavaScript之詞法作用域與作用域鏈》
1.什么是閉包

閉包的含義就是閉合,包起來,簡單的來說,就是一個(gè)具有封閉功能與包裹功能的結(jié)構(gòu)。所謂的閉包就是一個(gè)具有封閉的對外不公開的,包裹結(jié)構(gòu),或空間。

在JS中函數(shù)構(gòu)成閉包。一般函數(shù)是一個(gè)代碼結(jié)構(gòu)的封閉結(jié)構(gòu),即包裹的特性,同時(shí)根據(jù)作用域規(guī)則只允許函數(shù)訪問外部的數(shù)據(jù),外部無法訪問函數(shù)內(nèi)部的數(shù)據(jù),即封閉的對外不公開的特性,因此說函數(shù)可以構(gòu)成閉包。

概括:閉包就是一個(gè)具有封閉與包裹功能的結(jié)構(gòu)。函數(shù)可以構(gòu)成閉包。函數(shù)內(nèi)部定義的數(shù)據(jù)函數(shù)外部無法訪問,即函數(shù)具有封閉性;函數(shù)可以封裝代碼即具有包裹性,所以函數(shù)可以構(gòu)成閉包。
2.閉包有什么用(解決什么問題)?

閉包不允許外部訪問

要解決的問題就是間接訪問該數(shù)據(jù)

函數(shù)就可以構(gòu)成閉包,要解決的問題就是如何訪問到函數(shù)內(nèi)部的數(shù)據(jù)

function foo () {
    var num  = 123;
    return num;
}
var res = foo();
console.log( res );    // =>123

這里的確是訪問到函數(shù)中的數(shù)據(jù)了。但是該數(shù)據(jù)不能第二次訪問,因此第二次訪問的時(shí)候又要調(diào)用一次foo,表示又有一個(gè)新的num = 123出來了。

在函數(shù)內(nèi)的數(shù)據(jù),不能直接在函數(shù)外部訪問,那么在函數(shù)內(nèi)如果定義一個(gè)函數(shù),那么在這個(gè)函數(shù)內(nèi)部中是可以直接訪問的

function foo() {
    var num = Math.random();
    function func() {
        return mun;
    }
    return func;
}
var f = foo();
// f 可以直接訪問這個(gè) num
var res1 = f();
var res2 = f();

我們使用前面學(xué)習(xí)的繪制作用域鏈結(jié)構(gòu)圖的方法來繪制閉包的作用域鏈結(jié)構(gòu)圖,如下:

3.閉包使用舉例

如何獲得超過一個(gè)數(shù)據(jù)

function foo () {
    var num1 = Math.random();
    var num2 = Math.random();
    return {
        num1: function () {
            return num1;
        },
        num2: function () {
            return num2;
        }
    }
}

如何完成讀取一個(gè)數(shù)據(jù)和修改這個(gè)數(shù)據(jù)

function foo () {
    var num = Math.random();
    return {
        get_num : function () {
            return num;
        },
        set_num: function( value ) {
            return num = value;
        }
    }
}
4.基本的閉包結(jié)構(gòu)

一般閉包的問題就是要想辦法簡潔的獲取函數(shù)內(nèi)的數(shù)據(jù)使用權(quán),那么我們就可以總結(jié)出一個(gè)基本的使用模型。

寫一個(gè)函數(shù),函數(shù)內(nèi)部定義一個(gè)新函數(shù),返回新函數(shù),用新函數(shù)獲得函數(shù)內(nèi)的數(shù)據(jù)

寫一個(gè)函數(shù),函數(shù)內(nèi)部定義個(gè)一個(gè)對象,對象中綁定多個(gè)函數(shù)(方法),返回對象,利用對象的方法訪問函數(shù)內(nèi)的數(shù)據(jù)

5.閉包的基本用法

閉包是為了實(shí)現(xiàn)具有私有訪問空間的函數(shù)的

帶有私有訪問數(shù)據(jù)的對象

function Person() {
    this.name = "張三";
    // setName( "" )
}

所有的私有數(shù)據(jù),就是說只有函數(shù)內(nèi)部可以訪問的數(shù)據(jù),或?qū)ο髢?nèi)部的方法可以訪問的數(shù)據(jù)

最簡單的實(shí)現(xiàn):

function createPerson() {
    var __name__ = "";
    return {
        getName: function () {
            return __name__;
        },
        setName: function( value ) {
            // 如果不姓張就報(bào)錯(cuò)
            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.沙箱模式(閉包應(yīng)用的一個(gè)典范) 7.1 沙箱的概念

沙盤與盒子,就可以在一個(gè)笑笑的空間內(nèi)模擬顯示世界,特點(diǎn)是執(zhí)行效果與現(xiàn)實(shí)世界一模一樣,但是在沙箱中模擬與現(xiàn)實(shí)無關(guān).

7.2 沙箱模式

沙箱模式就是一個(gè)自調(diào)用函數(shù),代碼寫到函數(shù)中一樣會執(zhí)行,但是不會與外界有任何的影響

例如,在jQuery中

(function () {
   var jQuery = function () { // 所有的算法 }
   // .... // .... jQuery.each = function () {}
   window.jQuery = window.$ = jQuery;
})();
$.each( ... )
8.帶有緩存功能的函數(shù)

以 Fibonacci 數(shù)列為例,改進(jìn)傳統(tǒng)計(jì)算斐波那契數(shù)列方法
我們來回顧一下傳統(tǒng)遞歸方式求斐波那契數(shù)列方法,我們定義一個(gè)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

當(dāng) n = 5 式,count = 15,當(dāng)時(shí)當(dāng) n = 20 的時(shí)候,count就達(dá)到驚人的21891次,性能太低了

性能低的原因是 重復(fù)計(jì)算。如果每次將計(jì)算的結(jié)果存起來

那么每次需要的時(shí)候先看看有沒有存儲過該數(shù)據(jù),如果有,直接拿來用。

如果沒有再遞歸,但是計(jì)算的結(jié)果需要再次存儲起來,以便下次使用

改進(jìn)版:

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

改進(jìn)之后, n = 100的時(shí)候也才199次,大大提高了性能。

9.閉包的性能問題

函數(shù)執(zhí)行需要內(nèi)存,那么函數(shù)中定義的變量,會在函數(shù)執(zhí)行結(jié)束后自動回收,凡是因?yàn)殚]包結(jié)構(gòu)的,被引出的數(shù)據(jù),如果還有變量引用這些數(shù)據(jù)的話,那么這些數(shù)據(jù)就不會被回收。

因此在使用閉包的時(shí)候如果不適用某學(xué)數(shù)據(jù)了,一定要賦值一個(gè)null

var f = (function () {
    var num = 123;
    return function () {
        return num;
    };
})();
// f 引用著函數(shù),函數(shù)引用著變量num
// 因此在不適用該數(shù)據(jù)的時(shí)候,最好寫上
f = null;

推薦閱讀

進(jìn)擊JavaScript之(一)詞法作用域與作用域鏈

進(jìn)擊JavaScript之(二)詞法作用域與作用域鏈

進(jìn)擊JavaScript之(四)原型與原型鏈

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/80183.html

相關(guān)文章

  • 進(jìn)擊JavaScript(一)變量聲明提升

    摘要:如下代碼輸出的結(jié)果是代碼執(zhí)行分為兩個(gè)大步預(yù)解析的過程代碼的執(zhí)行過程預(yù)解析與變量聲明提升程序在執(zhí)行過程中,會先將代碼讀取到內(nèi)存中檢查,會將所有的聲明在此進(jìn)行標(biāo)記,所謂的標(biāo)記就是讓解析器知道有這個(gè)名字,后面在使用名字的時(shí)候不會出現(xiàn)未定義的錯(cuò)誤。 showImg(https://segmentfault.com/img/remote/1460000012922850); 如下代碼輸出的結(jié)果是...

    LeexMuller 評論0 收藏0
  • 進(jìn)擊JavaScript(二)詞法作用域與作用域鏈

    摘要:一作用域域表示的就是范圍,即作用域,就是一個(gè)名字在什么地方可以使用,什么時(shí)候不能使用。概括的說作用域就是一套設(shè)計(jì)良好的規(guī)則來存儲變量,并且之后可以方便地找到這些變量。 一、作用域 域表示的就是范圍,即作用域,就是一個(gè)名字在什么地方可以使用,什么時(shí)候不能使用。想了解更多關(guān)于作用域的問題推薦閱讀《你不知道的JavaScript上卷》第一章(或第一部分),從編譯原理的角度說明什么是作用域。概...

    denson 評論0 收藏0
  • 進(jìn)擊JavaScript(四)原型與原型鏈

    摘要:每一個(gè)由構(gòu)造函數(shù)創(chuàng)建的對象都會默認(rèn)的連接到該神秘對象上。在構(gòu)造方法中也具有類似的功能,因此也稱其為類實(shí)例與對象實(shí)例一般是指某一個(gè)構(gòu)造函數(shù)創(chuàng)建出來的對象,我們稱為構(gòu)造函數(shù)的實(shí)例實(shí)例就是對象。表示該原型是與什么構(gòu)造函數(shù)聯(lián)系起來的。 本文您將看到以下內(nèi)容: 傳統(tǒng)構(gòu)造函數(shù)的問題 一些相關(guān)概念 認(rèn)識原型 構(gòu)造、原型、實(shí)例三角結(jié)構(gòu)圖 對象的原型鏈 函數(shù)的構(gòu)造函數(shù)Function 一句話說明什么...

    XBaron 評論0 收藏0
  • 進(jìn)擊JavaScript(五) 立即執(zhí)行函數(shù)與閉包

    摘要:匿名函數(shù)是不能單獨(dú)寫的,所以就提不上立即執(zhí)行了。六立即執(zhí)行函數(shù)在閉包中的應(yīng)用立即執(zhí)行函數(shù)能配合閉包保存狀態(tài)。來看下上節(jié)內(nèi)容中閉包的例子現(xiàn)在,我們來利用立即執(zhí)行函數(shù)來簡化它第一個(gè)匿名函數(shù)執(zhí)行完畢后,返回了第二個(gè)匿名函數(shù)。 前面的閉包中,提到與閉包相似的立即執(zhí)行函數(shù),感覺兩者還是比較容易弄混吧,嚴(yán)格來說(因?yàn)橄透叱虒﹂]包的定義不同),立即執(zhí)行函數(shù)并不屬于閉包,它不滿足閉包的三個(gè)條件。...

    vincent_xyb 評論0 收藏0
  • 進(jìn)擊JavaScript(四) 閉包

    摘要:此時(shí)產(chǎn)生了閉包。導(dǎo)致,函數(shù)的活動對象沒有被銷毀。是不是跟你想的不一樣其實(shí),這個(gè)例子重點(diǎn)就在函數(shù)上,這個(gè)函數(shù)的第一個(gè)參數(shù)接受一個(gè)函數(shù)作為回調(diào)函數(shù),這個(gè)回調(diào)函數(shù)并不會立即執(zhí)行,它會在當(dāng)前代碼執(zhí)行完,并在給定的時(shí)間后執(zhí)行。 上一節(jié)說了執(zhí)行上下文,這節(jié)咱們就乘勝追擊來搞搞閉包!頭疼的東西讓你不再頭疼! 一、函數(shù)也是引用類型的。 function f(){ console.log(not cha...

    Anleb 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<