JS基礎(chǔ)核心之閉包

1. 閉包是什么?

function A () { // chrome認為的閉包是A函數(shù)
  var num = 1
  return function B () {
    console.log(num)
  }
}
var C = A ()
// 函數(shù)A中的變量num被全局函數(shù)C引用著,以至于不會被垃圾回收機制回收
C() // 1 // 大多數(shù)書籍理解的閉包是C函數(shù)

在A函數(shù)中嵌套B函數(shù),B函數(shù)訪問A函數(shù)中的變量。將A函數(shù)復(fù)制給C函數(shù)并執(zhí)行。

那么在大多數(shù)的理解中,包括許多著名的書籍,文章里都以函數(shù)C的名字代指這里生成的閉包。而在chrome中,則以執(zhí)行上下文A的函數(shù)名代指閉包。

而我的理解是:閉包更準確的說是一項技術(shù)或者一個特性:只要運用具備阻止垃圾回收機制回收和突破作用域鏈限制的技術(shù),就是閉包。像是《JavaScript權(quán)威指南》打的比方,像是把變量包裹了起來,形象的稱為“閉包”。

如果非要指明哪個函數(shù)是閉包的話,我愿意將A函數(shù)稱為定義閉包的函數(shù),C函數(shù)為執(zhí)行閉包的函數(shù)。

2 生成閉包的條件是什么?

function foo() { // 定義閉包
    var a = 10;
    function baz() {
      console.log(a);
    }
    baz(); // 被確認創(chuàng)建閉包
}

baz();

a. 在函數(shù)內(nèi)部創(chuàng)建新的函數(shù);

b. 新的函數(shù)在執(zhí)行時,訪問了函數(shù)的變量對象。

c. 閉包是在函數(shù)被調(diào)用執(zhí)行的時候才被確認創(chuàng)建的。

一句話總結(jié):==函數(shù)中閉包判定的準則,即執(zhí)行時是否在內(nèi)部定義的函數(shù)中訪問了上層作用域的變量。==

3. 閉包的作用是什么?

閉包,阻止垃圾回收機制。

閉包,突破作用域鏈接。

4 閉包的應(yīng)用

模塊模式

《你不知道的JS中》的示例:

function coolModule () {
  // 私有變量和函數(shù)
  var something = 'cool';
  var another = [1, 2, 3]
  function doSomething () {
    console.log(something)
  }
  function doAnother () {
    console.log(another.join('!'))
  }
  // 公開方法
  return {
    doSomething,
    doAnother
  }
})
var foo = coolModule ()
foo.doSomething() // cool
foo.doAnother() // 1!2!3

模塊模式需要具備兩個必要條件:

1.必須有外部的封閉函數(shù),該函數(shù)必須至少被調(diào)用一次(每次調(diào)用都會創(chuàng)建一個新的模塊實例)。

2.封閉函數(shù)必須返回至少一個內(nèi)部函數(shù),這樣內(nèi)部函數(shù)才能在私有作用域中形成閉包,并且可以訪問或者修改私有的狀態(tài)。

什么時候使用模塊模式?

如果必須創(chuàng)建一個對象并一某些數(shù)據(jù)對其進行初始化,同時還要公開一些能夠訪問這些私有數(shù)據(jù)的方法,那么就可以使用模塊模式。

哪些地方有用到模塊模式?

最典型的就是JQuery庫,jQuery和$標識符就是JQuery模塊的公共API,但它們本身都是函數(shù)(由于函數(shù)也是對象,它們本身也可以擁有屬性)

以后單獨拿一個章節(jié),來具體講講現(xiàn)在的模塊化和未來的模塊化機制。

柯里化

具體的內(nèi)容在函數(shù)的柯里化的章節(jié)中詳細分析。

戳此傳送門

面試題

  1. 防抖和節(jié)流
    戳此傳送門
  1. 定時器
for (var i = 1; i <= 5; i++) {
  setTimeout(function timer() {
    console.log(i); // 5次6
  }, i * 1000);
}

輸出6的原因是:被封閉在一個共享的全局作用域中,實際上只有一個i。

for (var i = 1; i <= 5; i++) {
  (function (j) {
    setTimeout(function timer() {
      console.log(j); // 依次輸出1至5
    }, i * 1000);
  })(i)
}

依次輸出1-5的原因是:在迭代內(nèi)部使用IIFE(立即表達函數(shù))為每個迭代生成一個新的作用域,將外部變量的值傳遞進去并被引用(阻止垃圾回收機制回收),使得每個回調(diào)函數(shù)都能訪問到正確值的變量。

  1. jn-toast組件認識閉包

戳此傳送門

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

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