bl双性强迫侵犯h_国产在线观看人成激情视频_蜜芽188_被诱拐的少孩全彩啪啪漫画

JavaScript中閉包的案例分析-創(chuàng)新互聯(lián)

小編給大家分享一下JavaScript中閉包的案例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

成都創(chuàng)新互聯(lián)公司主營(yíng)沿灘網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營(yíng)網(wǎng)站建設(shè)方案,重慶APP軟件開發(fā),沿灘h5重慶小程序開發(fā)搭建,沿灘網(wǎng)站營(yíng)銷推廣歡迎沿灘等地區(qū)企業(yè)咨詢

前言

想要深入學(xué)習(xí)JavaScript這門語(yǔ)言,閉包這個(gè)概念幾乎是繞不開的關(guān)鍵,今天就讓我們一起好好地盤一盤,閉包到底是什么東西。
如果是零基礎(chǔ)的小伙伴,可以先看看前一篇文章,幫助你更好的理解本文的內(nèi)容:

  • 【JavaScript】有趣的作用域和提升

了解一下閉包

1. 什么是閉包

我們先來(lái)看看閉包在MDN中的定義:

一個(gè)函數(shù)和對(duì)其周圍狀態(tài)(lexical environment,詞法環(huán)境)的引用捆綁在一起(或者說(shuō)函數(shù)被引用包圍),這樣的組合就是閉包(closure)

閉包的定義非常晦澀難懂,如果通俗的解釋一下的話,就是:

  • 一個(gè)定義在函數(shù)內(nèi)部的函數(shù)和所在作用域的組合稱為閉包。  

這么講可能還是非常抽象,不過(guò)我們先有個(gè)概念,下面會(huì)詳細(xì)解釋這個(gè)概念。對(duì)于閉包,其實(shí)還有另一種解釋:

  • 一個(gè)函數(shù)中聲明了一個(gè)內(nèi)部函數(shù)并返回,外部可以通過(guò)這個(gè)內(nèi)部函數(shù)訪問(wèn)到內(nèi)部的值,這樣的函數(shù),我們稱作閉包

區(qū)別于第一種解釋,第二種解釋把函數(shù)本身稱作為閉包,這樣的解釋也合理,但更準(zhǔn)確的話其實(shí)我們可以把這個(gè)函數(shù)稱作閉包函數(shù)。這樣的話,其實(shí)兩種解釋都沒(méi)有問(wèn)題,也可以同時(shí)存在了。

2. 感受一下閉包

看完了閉包的概念,我們通過(guò)實(shí)際的例子感受一下,閉包長(zhǎng)什么樣?閉包產(chǎn)生的條件?

閉包長(zhǎng)什么樣?
function outer(){    var a=0;    function inner(){        console.log(++a);
    }    return inner;
}var f=outer();
f();  //1f();  //2復(fù)制代碼

我們先來(lái)看下這個(gè)例子里,閉包是如何體現(xiàn)的。我們首先定義了outer函數(shù),然后在outer函數(shù)的內(nèi)部聲明了一個(gè)inner函數(shù)并返回。

在外部,我們執(zhí)行outer函數(shù),并將返回的inner函數(shù)保存在了f中,現(xiàn)在的f就是我們說(shuō)的閉包函數(shù)了。

在例子中,我們執(zhí)行了兩次f函數(shù),分別輸出了12,說(shuō)明我們?cè)趫?zhí)行f函數(shù)中的console.log(++a);語(yǔ)句時(shí),根據(jù)我們之前對(duì)作用域的解釋,會(huì)去函數(shù)所在的作用域鏈上尋找變量,最終在outer函數(shù)中找到了這個(gè)變量,并進(jìn)行了增值操作。

同時(shí)需要注意的是,我們輸出的結(jié)果并不是兩次1,說(shuō)明我們的作用域是共享的,可以看成outer的作用域延伸到了外部。

outer作用域本來(lái)應(yīng)該在執(zhí)行結(jié)束后釋放,但根據(jù)GC機(jī)制(我們這里先不展開介紹)會(huì)發(fā)現(xiàn):

  • 我準(zhǔn)備釋放outer了,但a變量好像被引用了,而且外部還保存了起來(lái)不知道什么時(shí)候調(diào)用?好叭,那我就先不釋放了。

閉包就這樣誕生了,在作用域消失之后,外部依然可以訪問(wèn)作用域中的變量

閉包產(chǎn)生的條件?

我們根據(jù)剛剛的例子和解釋總結(jié)一下,產(chǎn)生一個(gè)閉包需要哪些條件:

  1. 在外部函數(shù)中聲明一個(gè)內(nèi)部函數(shù),并返回內(nèi)部函數(shù)。
    這里的outer就是外部函數(shù),inner就是返回的內(nèi)部函數(shù)。
  2. 內(nèi)部的函數(shù)引用了外部函數(shù)中的變量。
    我們的例子中,inner函數(shù)就引用了變量a。
  3. 外部函數(shù)需要被執(zhí)行,創(chuàng)建一個(gè)閉包,同時(shí)返回的內(nèi)部函數(shù)需要被保存起來(lái)。
    外部函數(shù)outer需要被執(zhí)行,同時(shí)需要把返回的內(nèi)部函數(shù)給保存起來(lái),也就是我們例子中的var f=outer()。

只有同時(shí)滿足了這三個(gè)條件,才能產(chǎn)生閉包。看似很難達(dá)成,事實(shí)上,我們實(shí)際代碼中經(jīng)常不經(jīng)意間就能產(chǎn)生閉包。

通過(guò)剛剛的介紹,相信大家應(yīng)該對(duì)閉包有了一個(gè)概念,接下來(lái)就讓我們出發(fā),深入的了解一下閉包的方方面面。

深入體驗(yàn)一下閉包

1.創(chuàng)建多個(gè)閉包

在剛剛的例子中,我們創(chuàng)建了一個(gè)閉包,執(zhí)行多次閉包函數(shù)后,增加的都是同一個(gè)作用域中的變量a,那么我們?cè)囋噭?chuàng)建多個(gè)閉包會(huì)怎么樣:

function outer() {  var a = 0;  function inner() {    console.log(++a);
  }  return inner;
}var f1 = outer();var f2 = outer();
f1();  //1f2();  //1復(fù)制代碼

這段代碼在剛剛的例子上進(jìn)行了改動(dòng),我們執(zhí)行了兩次外部函數(shù)outer,并分別用不同的變量f1f2保存。當(dāng)執(zhí)行f1f2時(shí)會(huì)發(fā)現(xiàn),輸出的結(jié)果都是1,說(shuō)明f1f2的作用域是獨(dú)立的,f1f2屬于兩個(gè)不同的閉包,我們用一張圖來(lái)理解下:JavaScript中閉包的案例分析

當(dāng)分別創(chuàng)建f1f2時(shí),調(diào)用了兩次outer函數(shù),創(chuàng)建了兩個(gè)不同的上下文。而當(dāng)f1f2分別執(zhí)行時(shí),根據(jù)作用域的查找規(guī)則,會(huì)去對(duì)應(yīng)的作用域中查找變量,并執(zhí)行增值輸出,所以最終兩個(gè)值均為2;

2.使用閉包實(shí)現(xiàn)模塊化

我們知道,作用域的外部無(wú)法拿到作用域內(nèi)部的值,而通過(guò)閉包,我們可以把作用域我們需要的值或者方法暴露出去,比如:

function outer() {  var myNumber = 0;  function addNumber() {
    myNumber++;
  }  function getNumber() {    return myNumber;
  }  return {
    addNumber, getNumber
  }
}var module = outer();module.addNumber();module.addNumber();module.getNumber();復(fù)制代碼

在這個(gè)例子中,我們同樣定義了一個(gè)外部函數(shù)outer,另外還分別定義了兩個(gè)函數(shù)addNumbergetNumber,用于增加和獲取變量myNumber。

當(dāng)我們執(zhí)行outer()語(yǔ)句的時(shí)候,會(huì)創(chuàng)建一個(gè)上下文,同時(shí)把內(nèi)部返回的對(duì)象保存在module變量上,此時(shí)我們就創(chuàng)建了一個(gè)閉包,以及一個(gè)包含方法addNumbergetNumber的對(duì)象。

由于外部是無(wú)法直接訪問(wèn)變量myNumber的,但由于閉包的原因,addNumbergetNumber是可以訪問(wèn)到這個(gè)變量的,因此我們成功的把變量myNumber隱藏了起來(lái),并且對(duì)外只提供了增加和獲取myNumber值的方法。

試著用閉包解決問(wèn)題

通過(guò)剛剛的例子,相信大家應(yīng)該對(duì)閉包有了一定了解,接下來(lái)我們?cè)囍\(yùn)用閉包來(lái)解決實(shí)際問(wèn)題,先看一下例子:

for (var i = 0; i < 2; i++) {      setTimeout(() => {        console.log(i);
      }, 500);
    }復(fù)制代碼

這是一個(gè)十分容易令人誤解的例子。接觸過(guò)的小伙伴肯定都知道,最后會(huì)輸出兩次2而不是依次輸出01,我們來(lái)看看為什么會(huì)這樣。
首先,外部是一個(gè)for循環(huán),執(zhí)行了兩次語(yǔ)句。

for (var i = 0; i < 2; i++) {
    ... //  執(zhí)行兩次}復(fù)制代碼

在函數(shù)的內(nèi)部,我們調(diào)用了setTimeout函數(shù),關(guān)鍵的地方來(lái)了,這個(gè)函數(shù)是一個(gè)異步函數(shù),并不會(huì)馬上執(zhí)行,所以實(shí)際上等外部的for循環(huán)執(zhí)行結(jié)束了,才會(huì)真的執(zhí)行setTimeout中的函數(shù)。還有第二個(gè)關(guān)鍵點(diǎn)在于,for循環(huán)中,var定義的變量相當(dāng)于定義在全局,而不存在塊級(jí)作用域。那么剛剛的代碼就可以近似的看成這樣了。

var i=0;
i++;    //i=1i++;    //i=2console.log(i);console.log(i);復(fù)制代碼

非常直接粗暴,但可以很清晰的看出輸出結(jié)果為何是兩次2了,因?yàn)榇蠹夜灿昧送粋€(gè)作用域,i的值被覆蓋了。那么知道了問(wèn)題出在哪里,我們?cè)囍蒙衔覀儎倓倢W(xué)習(xí)的閉包,來(lái)創(chuàng)建不同的作用域:

   for (var i = 0; i < 2; i++) {      function outer() {        var j = i;        setTimeout(function inner() {          console.log(j);
        }, 500);
      }
      outer();
    }復(fù)制代碼

我們按照閉包的樣式對(duì)剛剛的代碼進(jìn)行了改造,這里的setTimeout并不直接就是inner函數(shù),這是因?yàn)樗谶@里起到了定義inner函數(shù),并保存執(zhí)行inner函數(shù)的功能。

我們可以看到,最終結(jié)果依次輸出了01,說(shuō)明我們的閉包是成功了的,但這樣的閉包比較臃腫,我們?cè)囍岣咭幌拢瑢懙母觾?yōu)雅一點(diǎn):

   for (var i = 0; i < 2; i++) {
        (function() {   //用自執(zhí)行函數(shù)代替了`outer`函數(shù)的定義和執(zhí)行兩個(gè)步驟
            var j = i;            setTimeout(function inner() {                console.log(j);
            }, 500);
        })();
    }復(fù)制代碼

還可以再簡(jiǎn)化一下:

for (var i = 0; i < 5; i++) {        for (var i = 0; i < 2; i++) {
            (function(j) {//用自執(zhí)行函數(shù)代替了`outer`函數(shù)的定義和執(zhí)行兩個(gè)步驟
                setTimeout(function inner() {                    console.log(j);
                }, 500);
            })(i);//var j=i的步驟,通過(guò)傳入i值替換
        }
    }復(fù)制代碼

這樣就大功告成了!

以上是JavaScript中閉包的案例分析的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)-成都網(wǎng)站建設(shè)公司行業(yè)資訊頻道!

本文標(biāo)題:JavaScript中閉包的案例分析-創(chuàng)新互聯(lián)
轉(zhuǎn)載來(lái)于:http://vcdvsql.cn/article4/phsoe.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供建站公司網(wǎng)站建設(shè)、標(biāo)簽優(yōu)化網(wǎng)頁(yè)設(shè)計(jì)公司電子商務(wù)、網(wǎng)站改版

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都做網(wǎng)站