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

資訊專欄INFORMATION COLUMN

JavaScript中的閉包

AaronYuan / 1712人閱讀

摘要:但是,不合理地濫用閉包,也會造成很多性能問題,從而使項(xiàng)目維護(hù)成本增加。

前言

相信很多小伙伴在工作或者面試過程中都遇到過這個(gè)問題,作為經(jīng)典的前端面試題之一,它高頻地出現(xiàn)在我們的求職生涯中。所以,了解和掌握它也就變得十分必要了

讀完這篇文章,你或許就會知道:

閉包是什么,它是怎么形成的

為什么要使用閉包

閉包會造成哪些問題

如果文章中有出現(xiàn)紕漏、錯(cuò)誤之處,還請看到的小伙伴多多指教,先行謝過

以下↓

作用域

what? 不是在說閉包么,怎么又扯到作用域上面去了

稍安勿躁,在我們了解閉包之前,還是很有必要先了解一下 JavaScript 中的作用域

我們都知道在 JavaScript 中存在著全局變量和局部變量,全局變量可以在任何地方訪問到,然而局部變量只能在當(dāng)前作用域中訪問。全局作用域是不能直接訪問局部作用域中的變量,而局部作用域可以直接訪問全局作用域當(dāng)中的變量

就像一個(gè)代碼塊兒或函數(shù)被嵌套在另一個(gè)代碼塊兒或函數(shù)中一樣,作用域也會被嵌套在其他的作用域中。所以,如果在直接作用域中找不到一個(gè)變量的話,就會咨詢下一個(gè)外層作用域,如此繼續(xù)直到找到這個(gè)變量或者到達(dá)最外層作用域(也就是全局作用域)

說了這么多,其實(shí)說白了,所謂 作用域就是一組規(guī)則,它決定了一個(gè)變量(標(biāo)識符)在哪里和如何被查找

試想一下,現(xiàn)在有一個(gè)這樣的需求:我們想在全局作用域拿到局部作用域的某一個(gè)變量該怎么去做呢?

初識閉包
JavaScript 中閉包無所不在,你只是必須認(rèn)出它并接納它

正常情況下,我們并不能拿到局部作用域的變量。但是,我們可以使用變通的方式:定義一個(gè)函數(shù)

讓我們看一下這段代碼

function foo() {
    var a = 2;
    function bar() {
        console.log( a ); // 2
    }
}

這樣在函數(shù) foo 中定義一個(gè) bar 函數(shù),在這個(gè)函數(shù)中我們就能訪問到定義在函數(shù) foo 中的變量 a 。既然我們這樣就可以訪問到 foo 函數(shù)里面的變量,那么,只要我們將 bar 這個(gè)函數(shù)作為返回值輸出,不就實(shí)現(xiàn)我們的需求了么? 是的!

function foo() {
    var a = 2;
    function bar() {
        console.log( a ); // 2
    }
    return bar
}

var result = foo();

result() // 2

這就是閉包

讓我們來看看這個(gè)函數(shù)做了什么:

創(chuàng)建了一個(gè)函數(shù) foo

函數(shù)里面創(chuàng)建了一個(gè)變量 a 與函數(shù) bar

返回函數(shù) bar

現(xiàn)在,我們就對閉包有了一個(gè)基本的概念:定義在一個(gè)函數(shù)內(nèi)部的函數(shù)

再遇閉包
詞法作用域:簡單理解為作用域是由編寫時(shí)函數(shù)被聲明的位置定義的

還是來看一下下面的代碼

function foo() {
    var a = 2;
    function baz() {
        console.log( a ); // 2
    }
    bar( baz );
}

function bar(fn) {
    fn(); 
}

與前面示例不同的是,這里我們并沒有將函數(shù) baz 返回,而是將它當(dāng)做值傳遞給 bar 這個(gè)函數(shù),然后在 bar 這個(gè)函數(shù)里面執(zhí)行,函數(shù) bar 保持了函數(shù) baz引用

相同的是,實(shí)際上函數(shù) baz 都在它被編寫時(shí)的詞法作用域之外被調(diào)用,bar() 依然擁有對那個(gè)作用域的引用,而這個(gè)引用稱為閉包

這就是閉包

好了,看到這里是不是還有點(diǎn)懵呢,讓我們再來看一個(gè)更加常見的示例

for(var i = 1; i <= 5; i++) {
    setTimeout(function() {
        console.log(i)
    }, 1000)
}

毫無疑問,運(yùn)行上面的代碼會輸出 5 個(gè) 6.很明顯,我們得到的結(jié)果是 i 在循環(huán)之后的最終值

那么,為什么會是這樣呢?

其實(shí),由于作用域的工作方式,我們在定時(shí)器函數(shù)中訪問到的 i 是共享到全局作用域的上的,它只有一個(gè),就是最終循環(huán)結(jié)束的值

想讓這個(gè)循環(huán)顯示我們想要的結(jié)果也很簡單,只需要這樣:

for(var i = 1; i <= 5; i++) {
    (function(j) {
        setTimeout(function() {
            console.log(j)
        }, 1000)
    })(i)
}

使用一個(gè)立即執(zhí)行函數(shù)將定時(shí)器函數(shù)包裹起來,在這個(gè)函數(shù)中定義一個(gè)變量 j,然后將 i 當(dāng)做值傳遞進(jìn)去。這樣,在每次迭代的時(shí)候,變量 j 都會擁有 i 的一個(gè)拷貝,自然得到了我們想要的結(jié)果

同樣的,這也是一個(gè)閉包

當(dāng)然,我們也可以使用 ES6 中的 let 關(guān)鍵字聲明變量 i

通過前面的一些示例,我們不難發(fā)現(xiàn):閉包其實(shí)并沒有特定的格式,只要滿足一些條件,它就是閉包

所以:

閉包就是當(dāng)一個(gè)函數(shù)即使是在它的詞法作用域之外被調(diào)用時(shí),也可以記住并訪問它的詞法作用域

閉包的用途

閉包最大的用途:

讀取函數(shù)內(nèi)部的變量

讓這些變量始終保存在內(nèi)存中

function f1(){
  var n=999;
  nAdd=function(){n+=1}
  function f2(){
    alert(n);
  }
  return f2;
}
var result=f1();
result(); // 999
nAdd();
result(); // 1000

在這段代碼中,result 實(shí)際上就是閉包 f2 函數(shù)。它一共運(yùn)行了兩次,第一次的值是 999 ,第二次的值是 1000 。這證明了,函數(shù) f1 中的局部變量 n 一直保存在內(nèi)存中,并沒有在 f1 調(diào)用后被自動清除

使用閉包模擬私有方法(數(shù)據(jù)隱藏和封裝)

私有方法不僅僅有利于限制對代碼的訪問:還提供了管理全局命名空間的強(qiáng)大能力,避免非核心的方法弄亂了代碼的公共接口部分

var Counter = (function() {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function() {
      changeBy(1);
    },
    decrement: function() {
      changeBy(-1);
    },
    value: function() {
      return privateCounter;
    }
  }   
})();

這個(gè)環(huán)境中包含兩個(gè)私有項(xiàng):名為 privateCounter 的變量和名為 changeBy 的函數(shù)。這兩項(xiàng)都無法在這個(gè)匿名函數(shù)外部直接訪問。必須通過匿名函數(shù)返回的三個(gè)公共函數(shù)訪問。

這三個(gè)公共函數(shù)是共享同一個(gè)環(huán)境的閉包

閉包的問題

閉包的用途在一定程度上也造成了很多問題,比如:閉包會使函數(shù)中的變量始終保存在內(nèi)存中,不能被 JavaScript 的垃圾回收清理,很容易造成內(nèi)存消耗過大,影響程序性能

后記

閉包的合理運(yùn)用,會讓我們在開發(fā)中寫出更優(yōu)雅和干凈的代碼。但是,不合理地濫用閉包,也會造成很多性能問題,從而使項(xiàng)目維護(hù)成本增加。

所以,如何合理地使用這個(gè)有趣的東西,還需要我們多多鉆研和摸索,相信你一定可以對它越來越熟悉

最后,推薦一波前端學(xué)習(xí)歷程,不定期分享一些前端問題和有意思的東西歡迎 star 關(guān)注 傳送門

參考文檔

You-Dont-Know-JS

閉包 - MDN

學(xué)習(xí)JavaScript閉包 - 阮一峰

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

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

相關(guān)文章

  • JavaScript中的閉包

    摘要:閉包引起的內(nèi)存泄漏總結(jié)從理論的角度將由于作用域鏈的特性中所有函數(shù)都是閉包但是從應(yīng)用的角度來說只有當(dāng)函數(shù)以返回值返回或者當(dāng)函數(shù)以參數(shù)形式使用或者當(dāng)函數(shù)中自由變量在函數(shù)外被引用時(shí)才能成為明確意義上的閉包。 文章同步到github js的閉包概念幾乎是任何面試官都會問的問題,最近把閉包這塊的概念梳理了一下,記錄成以下文章。 什么是閉包 我先列出一些官方及經(jīng)典書籍等書中給出的概念,這些概念雖然...

    HmyBmny 評論0 收藏0
  • JavaScript閉包,只學(xué)這篇就夠了

    摘要:當(dāng)在中調(diào)用匿名函數(shù)時(shí),它們用的都是同一個(gè)閉包,而且在這個(gè)閉包中使用了和的當(dāng)前值的值為因?yàn)檠h(huán)已經(jīng)結(jié)束,的值為。最好將閉包當(dāng)作是一個(gè)函數(shù)的入口創(chuàng)建的,而局部變量是被添加進(jìn)這個(gè)閉包的。 閉包不是魔法 這篇文章使用一些簡單的代碼例子來解釋JavaScript閉包的概念,即使新手也可以輕松參透閉包的含義。 其實(shí)只要理解了核心概念,閉包并不是那么的難于理解。但是,網(wǎng)上充斥了太多學(xué)術(shù)性的文章,對于...

    CoderBear 評論0 收藏0
  • 還擔(dān)心面試官問閉包?

    摘要:一言以蔽之,閉包,你就得掌握。當(dāng)函數(shù)記住并訪問所在的詞法作用域,閉包就產(chǎn)生了。所以閉包才會得以實(shí)現(xiàn)。從技術(shù)上講,這就是閉包。執(zhí)行后,他的內(nèi)部作用域并不會消失,函數(shù)依然保持有作用域的閉包。 網(wǎng)上總結(jié)閉包的文章已經(jīng)爛大街了,不敢說筆者這篇文章多么多么xxx,只是個(gè)人理解總結(jié)。各位看官瞅瞅就好,大神還希望多多指正。此篇文章總結(jié)與《JavaScript忍者秘籍》 《你不知道的JavaScri...

    tinyq 評論0 收藏0
  • JavaScript中的閉包

    摘要:權(quán)威指南第版中閉包的定義函數(shù)對象可以通過作用域鏈相互關(guān)聯(lián)起來,函數(shù)體內(nèi)部的變量都可以保存在函數(shù)作用域內(nèi),這種特性在計(jì)算機(jī)科學(xué)文獻(xiàn)中成為閉包。循環(huán)中的閉包使用閉包時(shí)一種常見的錯(cuò)誤情況是循環(huán)中的閉包,很多初學(xué)者都遇到了這個(gè)問題。 閉包簡介 閉包是JavaScript的重要特性,那么什么是閉包? 《JavaScript高級程序設(shè)計(jì)(第3版)》中閉包的定義: 閉包就是指有權(quán)訪問另一個(gè)函數(shù)中的變...

    Donne 評論0 收藏0
  • 深入javascript——作用域和閉包

    摘要:注意由于閉包會額外的附帶函數(shù)的作用域內(nèi)部匿名函數(shù)攜帶外部函數(shù)的作用域,因此,閉包會比其它函數(shù)多占用些內(nèi)存空間,過度的使用可能會導(dǎo)致內(nèi)存占用的增加。 作用域和作用域鏈?zhǔn)莏avascript中非常重要的特性,對于他們的理解直接關(guān)系到對于整個(gè)javascript體系的理解,而閉包又是對作用域的延伸,也是在實(shí)際開發(fā)中經(jīng)常使用的一個(gè)特性,實(shí)際上,不僅僅是javascript,在很多語言中都...

    oogh 評論0 收藏0
  • Javascript閉包入門(譯文)

    摘要:也許最好的理解是閉包總是在進(jìn)入某個(gè)函數(shù)的時(shí)候被創(chuàng)建,而局部變量是被加入到這個(gè)閉包中。在函數(shù)內(nèi)部的函數(shù)的內(nèi)部聲明函數(shù)是可以的可以獲得不止一個(gè)層級的閉包。 前言 總括 :這篇文章使用有效的javascript代碼向程序員們解釋了閉包,大牛和功能型程序員請自行忽略。 譯者 :文章寫在2006年,可直到翻譯的21小時(shí)之前作者還在完善這篇文章,在Stackoverflow的How do Java...

    Fourierr 評論0 收藏0

發(fā)表評論

0條評論

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