《你不知道的JavaScript》--閉包(04)

一、閉包

當(dāng)函數(shù)可以記住并訪問所在的詞法作用域時,就產(chǎn)生了閉包,即使函數(shù)是在當(dāng)前詞法作用域之外執(zhí)行。

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

上面的是閉包嗎?

確切的說并不是,在上面的代碼中,函數(shù)bar可以訪問foo作用域以及全局作用域,因?yàn)閎ar嵌套在函數(shù)內(nèi)部,但是這個并不是一個閉包。

function foo(){
  var a = 2;
  function bar(){
    console.log(a)  // 2
  }
  return bar()
}
var baz = foo();
baz(); // 2   這個才是閉包

函數(shù)bar() 的詞法作用域能夠訪問foo的內(nèi)部作用域,我們把函數(shù)bar()作為foo的返回值,在foo執(zhí)行之后,其返回值賦值給變量baz,調(diào)用baz,實(shí)際上就是通過不同的標(biāo)識符調(diào)用了內(nèi)部函數(shù)bar,bar可以被正常執(zhí)行。

在foo執(zhí)行之后,通常會期待foo的整個內(nèi)部作用域被銷毀,因?yàn)槲覀冎酪嬗欣厥掌饔脕磲尫挪辉偈褂玫膬?nèi)存空間,而閉包的神奇之處就在于阻止這樣的事情發(fā)生。因?yàn)閎ar本身還在使用foo內(nèi)部的變量,使得foo的作用域一直存在,一共bar在之后任何時間進(jìn)行引用。

bar依然持有該作用域的引用,而這個引用就叫做閉包。

即這個函數(shù)在定義時的詞法作用域以外的地方被調(diào)用,閉包使得函數(shù)可以繼續(xù)訪問定義時的詞法作用域。

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

無論通過任何手段將內(nèi)部函數(shù)傳遞到所在的詞法作用域以外,它都會持有對原始定義作用域的引用,無論在何處執(zhí)行這個函數(shù)都會使用閉包。

二、循環(huán)與閉包

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

這段代碼估計很多人面試的時候都見過,那你是怎么回答的呢?

延遲函數(shù)的回調(diào)在循環(huán)結(jié)束后才執(zhí)行。我們試圖假設(shè)循環(huán)中的每個迭代都會在運(yùn)行時候給自己‘捕獲’一個i的副本,但是根據(jù)作用域的工作原理,他們都在同一個作用域里,也就是說只有一個i,循環(huán)結(jié)束后是6,那么延遲函數(shù)執(zhí)行后獲取到的i就是6.

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

這樣行嗎?

當(dāng)然不行,因?yàn)楝F(xiàn)在雖然后更多的詞法作用域,每個延遲函數(shù)都會將IIFE每次迭代中創(chuàng)建的作用域封閉起來,但是此時作用域中是空的,并沒有i,所以還是都打印出6。

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

這樣就可以了。問題解決。

其實(shí)閉包還有很多用圖,甚至經(jīng)常看到閉包,通過這篇文章,能夠認(rèn)識閉包就是一種進(jìn)步。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 作用域 作用域是一套存儲、訪問變量的規(guī)則。這套規(guī)則用來管理引擎如何在當(dāng)前作用域以及嵌套的子作用域中根據(jù)標(biāo)識符名稱進(jìn)...
    獨(dú)木舟的木閱讀 459評論 0 0
  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持,譯者再次奉上一點(diǎn)點(diǎn)福利:阿里云產(chǎn)品券,享受所有官網(wǎng)優(yōu)惠,并抽取幸運(yùn)大...
    HetfieldJoe閱讀 5,711評論 16 88
  • 什么是閉包 《JavaScript高級程序設(shè)計第三版》:閉包是指有權(quán)訪問另一個函數(shù)作用域中的變量的函數(shù),創(chuàng)建閉包的...
    cfighter閱讀 564評論 1 1
  • 作用域閉包當(dāng)函數(shù)可以記住并訪問所在的詞法作用域時,就產(chǎn)生了閉包,即使函數(shù)式在當(dāng)前詞法作用域之外執(zhí)行。下面用一些代碼...
    xpwei閱讀 456評論 0 2
  • 【開卷有益】聽書《一平方米的靜心》 尋找職場中的小確幸,輕量級的正念練習(xí) 用心生活,發(fā)現(xiàn)生活中美好的是事情,你的態(tài)...
    小林日常閱讀 88評論 0 1

友情鏈接更多精彩內(nèi)容