JS中的閉包

什么是閉包?

(function(){
  var local = '你好'
  function fn(){
    console.log(local)
  }
})()

上面的代碼就形成了一個(gè)閉包:
「函數(shù)」和「函數(shù)內(nèi)部能訪(fǎng)問(wèn)到的變量」的總和验游,就是一個(gè)閉包
所以借卧,可以這么說(shuō),JS中所有的函數(shù)都是閉包敦姻。因?yàn)镴S中所有的函數(shù)都可以訪(fǎng)問(wèn)全局變量瘾境,那么全局變量和函數(shù)就形成了閉包
閉包不是故意弄出來(lái)的東西镰惦,而是JS函數(shù)作用域的副產(chǎn)品迷守。

函數(shù)作用域

ES 5 中只有兩種作用域,全局作用域和函數(shù)作用域旺入。函數(shù)內(nèi)部的變量可以讀取全局作用域中的變量兑凿,而函數(shù)外部不能讀取函數(shù)內(nèi)部定義的變量。而閉包眨业,就是溝通全局作用域和函數(shù)作用域之間的橋梁急膀,全局作用域和函數(shù)作用域通過(guò)閉包來(lái)實(shí)現(xiàn)變量的連接。

閉包的一般形式

常見(jiàn)的使用閉包的一般形式是使用自執(zhí)行函數(shù) 或 函數(shù)里面套函數(shù)龄捡,目的是為了提供一個(gè)函數(shù)作用域卓嫂,隔開(kāi)函數(shù)作用域和全局作用域,達(dá)到隱藏變量的目的聘殖。使用閉包將變量聲明放到函數(shù)作用域中晨雳,除了這個(gè)函數(shù)的其他地方就不能訪(fǎng)問(wèn)到這個(gè)變量,變量就隱藏了奸腺。

閉包的用途

  1. 讀取函數(shù)內(nèi)部變量
function foo(){
  var xx = '你好'
  return function(){
    return xx
  }
}
// 上面這段代碼中餐禁,函數(shù) foo 返回的匿名函數(shù)與 foo 中的變量 xx 形成了一個(gè)閉包。
// foo 返回一個(gè)匿名函數(shù)突照,該匿名函數(shù)讀取 foo 作用域中的變量帮非,之后返回該變量。
// 調(diào)用函數(shù) foo ,返回一個(gè)匿名函數(shù)末盔,再調(diào)用該匿名函數(shù)筑舅,就可以讀取 foo 中的變量。

var getVariable = foo()
getVariable()     //  返回  '你好'
console.log(xx)   // 報(bào)錯(cuò)陨舱,xx 沒(méi)有被定義
  1. 讓變量保持在內(nèi)存中翠拣,不被垃圾回收機(jī)制回收
function foo(xx){
  return function(){
    return xx++
  }
}
// 上面代碼中,使用閉包游盲,多創(chuàng)建了一個(gè)匿名函數(shù)的作用域來(lái)保存變量 xx 的值误墓。
// 在函數(shù) foo 執(zhí)行之后,xx 的值在匿名函數(shù)中被保留下來(lái)益缎,不會(huì)因?yàn)闆](méi)有被引用而被內(nèi)存回收 

var fn = foo(1)
fn()   // 1谜慌,每一次調(diào)用 fn,其實(shí)都是在調(diào)用 fn(foo 中返回的匿名函數(shù)) 作用域中的xx
fn()   // 2链峭,每一次調(diào)用 fn畦娄,其實(shí)都是在調(diào)用 fn(foo 中返回的匿名函數(shù)) 作用域中的xx
fn()   // 3,每一次調(diào)用 fn弊仪,其實(shí)都是在調(diào)用 fn(foo 中返回的匿名函數(shù)) 作用域中的xx
var li = document.querySelectorAll('li')
for(var i = 0; i < li.length; i++){
  li[i].onclick = function(){
    console.log(i)
  }
}
// 上面這段代碼,每一次點(diǎn)擊 li杖刷, 都會(huì)打印出 5
// 這是因?yàn)樯厦娴?i励饵,用的都是同一個(gè)作用域下的變量 i,這個(gè)作用域之中的 i滑燃,在經(jīng)過(guò) for 循環(huán)之后役听,值會(huì)變成 5。

// 而想要讓代碼達(dá)成我們想要的效果表窘,就需要為每一個(gè)變量 i 創(chuàng)建一個(gè)作用域典予,
// 使打印出來(lái)的每一個(gè)變量 i 的作用域不同,就是打印出不同的 i乐严,使用閉包就可以做到瘤袖。
var li = document.querySelectorAll('li')

for(var i = 0; i < li.length; i++){
  li[i].onclick = (function(i){
    return function(){
      console.log(i)
    }
  })(i)
}
// 上面代碼新增了一個(gè)函數(shù)作用域,用來(lái)保存變量 i 的值昂验。新增的函數(shù)返回要執(zhí)行的回調(diào)函數(shù)捂敌,
// 又因?yàn)?‘click’事件是直接執(zhí)行的,所以既琴,要將返回的函數(shù)直接執(zhí)行占婉,使用自執(zhí)行函數(shù)的方式,來(lái)執(zhí)行返回的回調(diào)函數(shù)甫恩。
// 這時(shí)調(diào)用的回調(diào)函數(shù)逆济,每一個(gè) i 都是獨(dú)立函數(shù)作用域之中的 i,它們的值都不一樣。
  1. 封裝私有變量奖慌、方法
function fn(a){
  var b = 'hi'
  
  function add(){
    return a++
  }
  
  function reduce(){
    return a--
  }
  
  function getA(){
     return a
  }
  
  function getB(){
    return b
  }
  
  function modefyB(x){
    b = x
    return b
  }
  
  return {
    getA: getA,
    add: add,
    reduce: reduce,
    getB: getB,
    modefyB: modefyB,
  }
}

// 上面的代碼封裝了兩個(gè)私有變量和4個(gè)私有方法抛虫。
// 一個(gè)私有變量是參數(shù)傳入的,一個(gè)私有變量是自身定義的升薯。
// 通過(guò)私有方法來(lái)對(duì)私有變量進(jìn)行操作莱褒。

var f1 = fn(1)
var f2 = fn(10)
// f1 和 f2 是兩個(gè)不同的對(duì)象,擁有各自的私有變量和私有方法涎劈,分別對(duì) f1 和 f2 進(jìn)行操作广凸,并不會(huì)影響另一個(gè)。

f1.getA()  // 1
f1.getB() // 'hi'
f1.modefyB('hello')
f1.getB()  // 'hello'

f2.getA()  // 10
f2.getB()  // 'hi'
f2.modefyB('放心蛛枚,我不會(huì)改變對(duì)象f1的谅海。不信你試試?')
f2.getB()  // '放心蹦浦,我不會(huì)改變對(duì)象f1的扭吁。不信你試試?'

f1.getB() // 'hello'
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末盲镶,一起剝皮案震驚了整個(gè)濱河市侥袜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌溉贿,老刑警劉巖枫吧,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異宇色,居然都是意外死亡九杂,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)宣蠕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)例隆,“玉大人,你說(shuō)我怎么就攤上這事抢蚀《撇悖” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵思币,是天一觀的道長(zhǎng)鹿响。 經(jīng)常有香客問(wèn)我,道長(zhǎng)谷饿,這世上最難降的妖魔是什么惶我? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮博投,結(jié)果婚禮上绸贡,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好听怕,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布捧挺。 她就那樣靜靜地躺著,像睡著了一般尿瞭。 火紅的嫁衣襯著肌膚如雪闽烙。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,688評(píng)論 1 305
  • 那天声搁,我揣著相機(jī)與錄音黑竞,去河邊找鬼。 笑死疏旨,一個(gè)胖子當(dāng)著我的面吹牛很魂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播檐涝,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼遏匆,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了谁榜?” 一聲冷哼從身側(cè)響起幅聘,我...
    開(kāi)封第一講書(shū)人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體级乐,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡罐孝,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了狞尔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片丛版。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖偏序,靈堂內(nèi)的尸體忽然破棺而出页畦,到底是詐尸還是另有隱情,我是刑警寧澤研儒,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布豫缨,位于F島的核電站,受9級(jí)特大地震影響端朵,放射性物質(zhì)發(fā)生泄漏好芭。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一冲呢、第九天 我趴在偏房一處隱蔽的房頂上張望舍败。 院中可真熱鬧,春花似錦、人聲如沸邻薯。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)厕诡。三九已至累榜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間灵嫌,已是汗流浹背壹罚。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留醒第,地道東北人渔嚷。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像稠曼,于是被迫代替她去往敵國(guó)和親形病。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 首先,js閉包對(duì)于哪怕是有很多年前端開(kāi)發(fā)經(jīng)驗(yàn)的人,也是很晦澀難懂的東西. 所以,我不敢保證能把你說(shuō)明白,但是如果你...
    火鍋伯南克閱讀 417評(píng)論 0 1
  • 在上一篇文章“執(zhí)行環(huán)境和作用域”中霞幅,我試著梳理了執(zhí)行環(huán)境和作用域的關(guān)系漠吻。但實(shí)際上,文章中并沒(méi)有提到作用域司恳,而是介紹...
    海痕閱讀 241評(píng)論 0 0
  • 今天研究了一波js中的閉包途乃,分享一下自己的理解。 一扔傅、變量的作用域 要理解閉包耍共,首先必須理解Javascript特...
    阿布_0caf閱讀 249評(píng)論 0 2
  • 前兩天和老同學(xué)吃飯,大家回顧這幾年自己的發(fā)展猎塞,有一個(gè)共識(shí):大學(xué)剛畢業(yè)前幾年试读,因?yàn)椴欢殘?chǎng)規(guī)則,走了很多彎路荠耽,如果當(dāng)...
    王二寶閱讀 150評(píng)論 0 0