摘要:本質(zhì)與解析當(dāng)函數(shù)可以記住并訪問所在的詞法作用域時(shí),就產(chǎn)生了閉包,即使函數(shù)是在當(dāng)前詞法作用域之外執(zhí)行。
本質(zhì)與解析
當(dāng)函數(shù)可以記住并訪問所在的詞法作用域時(shí),就產(chǎn)生了閉包,即使函數(shù)是在當(dāng)前詞法作用域之外執(zhí)行。
function outter() { var a = 1 function inner() { console.log(a) } return inner } var accept = outter() accept() // 1
在此例中,將內(nèi)部函數(shù)inner作為返回值,當(dāng)outter函數(shù)執(zhí)行后,賦值給accept,并且調(diào)用accept;實(shí)際上調(diào)用了inner函數(shù),它在自己定義的詞法作用域以外的地方執(zhí)行。
通常在outter函數(shù)執(zhí)行完成之后,由于js的垃圾回收機(jī)制,其內(nèi)部的作用域會(huì)被銷毀回收,但是由于閉包的存在,accept持有對(duì)inner的引用,而inner聲明的位置為outter的內(nèi)部作用域,因此該作用能夠一直存活
面試常見的閉包考題就是循環(huán)閉包。例如:
for (var i=0; i<=8; i++) { setTimeout(function () { console.log(i) },1000) }
正常情況下期待每隔一秒輸出1~8,但是實(shí)際每秒輸出一個(gè)9,其實(shí)不難理解,從執(zhí)行棧來(lái)看,延遲函數(shù)會(huì)在整個(gè)for循環(huán)執(zhí)行完成之后才會(huì)執(zhí)行,即使setTimeout設(shè)置的延遲時(shí)間是0,同時(shí)其被封閉在全局的作用域中的,因此每次得到的都是對(duì)全局i變量的引用,實(shí)際上只有一個(gè)i。
可以通過立即執(zhí)行函數(shù)將作用域封閉起來(lái),同時(shí)通過自己定義一個(gè)變量j在每次迭代中存儲(chǔ)i的值來(lái)解決這個(gè)問題,代碼如下:
for (var i=0; i<=8; i++) { (function () { var j = i setTimeout(function () { console.log(j) },1000) })(i) }
還有更加簡(jiǎn)單的解決方案,可以通過let聲明來(lái)劫持塊作用域,并且在這個(gè)塊作用域中聲明一個(gè)變量,代碼如下:
for (let i=0; i<=8; i++) { setTimeout(function () { console.log(i) },1000) }
for循環(huán)頭部的let聲明會(huì)有一個(gè)特殊行為,這個(gè)行為指出變量在循環(huán)的過程中不止被聲明一次,每次迭代都會(huì)聲明,隨后每次迭代都會(huì)使用上一個(gè)迭代結(jié)束時(shí)的值來(lái)初始化這個(gè)變量,這就意味著每次循環(huán)都會(huì)聲明一個(gè)新的i,且會(huì)將上一個(gè)迭代結(jié)束時(shí)的值賦給i
模塊模式與閉包模塊模式實(shí)例:
function module() { //封閉函數(shù) var arr = [1,2,3] function one() { console.log(arr.join("")) } function another() { arr.push(4) console.log(arr.join("")) } return { one: one, //內(nèi)部函數(shù) another: another } } var accept = module() accept.one() //123 創(chuàng)建一個(gè)新的模塊實(shí)例 accept.another() //1234 創(chuàng)建一個(gè)新的模塊實(shí)例
解析:module是一個(gè)函數(shù),需要通過調(diào)用它來(lái)創(chuàng)建一個(gè)模塊實(shí)例。其返回一個(gè){key:value}形式的對(duì)象,這個(gè)對(duì)象中包含內(nèi)部函數(shù)的引用,將其暴露提供調(diào)用,且module內(nèi)部數(shù)據(jù)變量是私有隱藏狀態(tài),這個(gè)對(duì)象返回值本質(zhì)上是這個(gè)模塊的公共API
分析得出模塊模式需要兩個(gè)必備條件:
必須有外部的封閉函數(shù),該函數(shù)必須至少被調(diào)用一次(每次調(diào)用都會(huì)創(chuàng)建一個(gè)新的模塊實(shí)例)
封閉函數(shù)必須返回至少一個(gè)內(nèi)部函數(shù),這樣內(nèi)部函數(shù)才能在私有作用域中形成閉包,并且可以訪問或者修改私有的狀態(tài)
模塊機(jī)制var MyModules = (function Manager() { var modules = {}; function define(name, deps, impl) { for (var i=0; i"one"和"another"兩個(gè)模塊都是通過公共API函數(shù)來(lái)定義,并且"another"接受"one"的實(shí)例作為參數(shù)注入,這就是模塊之間可以存在依賴關(guān)系
以上內(nèi)容是個(gè)人的一點(diǎn)總結(jié),如果有錯(cuò)誤或不嚴(yán)謹(jǐn)?shù)牡胤?,歡迎批評(píng)指正,如果喜歡,歡迎點(diǎn)贊收藏
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/88624.html
摘要:大名鼎鼎的閉包面試必問。閉包的作用是什么??吹介]包在哪了嗎閉包到底是什么五年前,我也被這個(gè)問題困擾,于是去搜了并總結(jié)下來(lái)。關(guān)于閉包的謠言閉包會(huì)造成內(nèi)存泄露錯(cuò)。閉包里面的變量明明就是我們需要的變量,憑什么說是內(nèi)存泄露這個(gè)謠言是如何來(lái)的因?yàn)椤? 本文為饑人谷講師方方原創(chuàng)文章,首發(fā)于 前端學(xué)習(xí)指南。 大名鼎鼎的閉包!面試必問。請(qǐng)用自己的話簡(jiǎn)述 什么是「閉包」。 「閉包」的作用是什么。 首先...
摘要:完美的閉包,對(duì),閉包就這么簡(jiǎn)單。這僅僅是閉包的一部分,閉包利用函數(shù)作用域達(dá)到了訪問外層變量的目的。此時(shí)一個(gè)完整的閉包實(shí)現(xiàn)了,的垃圾回收機(jī)制由于閉包的存在無(wú)法銷毀變量。 1.閉包是指有權(quán)訪問另一個(gè)函數(shù)作用域中的變量的函數(shù)。 上面這段話來(lái)自 javascript 高級(jí)程序設(shè)計(jì) 第三版 P178 。作者說閉包是一個(gè)函數(shù),它有訪問另一個(gè)函數(shù)作用域中的變量的能力。 2.函數(shù)訪問它被創(chuàng)建時(shí)所處的...
摘要:第二梯隊(duì)理解有了第一梯隊(duì)的認(rèn)識(shí),我們慢慢修正大腦中對(duì)閉包的認(rèn)識(shí)。理解這句話就可以很好的與閉包這兩個(gè)字關(guān)聯(lián)起來(lái)理解閉包這個(gè)概念了??偨Y(jié)第二梯隊(duì)理解閉包是一個(gè)有特定功能的函數(shù)。第四梯隊(duì)理解閉包通過訪問外部變量,一個(gè)閉包可以維持這些變量。 閉包 閉包的概念困惑了我很久,記得當(dāng)時(shí)我面試的時(shí)候最后一面有一個(gè)問題就是問題關(guān)于閉包的問題,然而到現(xiàn)在已經(jīng)完全不記得當(dāng)時(shí)的題目是啥了,但仍然能夠回憶起當(dāng)時(shí)...
摘要:到底什么是閉包這個(gè)問題在面試是時(shí)候經(jīng)常都會(huì)被問,很多小白一聽就懵逼了,不知道如何回答好。上面這么說閉包是一種特殊的對(duì)象。閉包的注意事項(xiàng)通常,函數(shù)的作用域及其所有變量都會(huì)在函數(shù)執(zhí)行結(jié)束后被銷毀。從而使用閉包模塊化代碼,減少全局變量的污染。 閉包,有人說它是一種設(shè)計(jì)理念,有人說所有的函數(shù)都是閉包。到底什么是閉包?這個(gè)問題在面試是時(shí)候經(jīng)常都會(huì)被問,很多小白一聽就懵逼了,不知道如何回答好。這個(gè)...
閱讀 1314·2021-11-04 16:09
閱讀 3516·2021-10-19 11:45
閱讀 2408·2021-10-11 10:59
閱讀 1022·2021-09-23 11:21
閱讀 2774·2021-09-22 10:54
閱讀 1149·2019-08-30 15:53
閱讀 2618·2019-08-30 15:53
閱讀 3490·2019-08-30 12:57