淺析JS閉包(Closure)與函數(shù)的柯里化(Currying)

先上版圖


塞爾達(dá) 荒野之息
//3月3號老任就要發(fā)售Switch了,還有塞爾達(dá)護(hù)航新作好激動呀,然而我并沒有錢買...

1、JS閉包

閉包在程序界是一個很抽象的概念,以至于被人稱為編程界的哈姆雷特,我們先來看看MDN對其的解釋

Closures are functions that refer to independent (free) variables (variables that are used locally, but defined in an enclosing scope). In other words, these functions 'remember' the environment in which they were created.

  • 閉包是一個函數(shù),特指那些可以訪問獨立變量的函數(shù)(這種獨立變量在本地使用,但是卻定義在一個封閉的作用域),換句話說這類函數(shù)能夠記憶創(chuàng)建它們時的環(huán)境

其實我個人理解更傾向于:

當(dāng)嵌套函數(shù)的引用傳遞給了嵌套函數(shù)作用域之外的變量,或者對象的屬性,此時就會形成一個閉包

嗯,解釋的很好,但我還是不知道這是個啥
那還是少廢話上代碼吧。。

function person() {
  var name = 'ergouzi';
  console.log(name);
}
person();
console.log(name);
輸出:
//ergouzi
//undefined

很普通的一個函數(shù),正常理解函數(shù)與變量的思維就是:函數(shù)執(zhí)行,定義變量,函數(shù)執(zhí)行完畢,變量銷毀。再來看看另一種寫法

function person() {
  var name = 'ergouzi';
  var nameFunc = function() {
    console.log(name);
  }
  return nameFunc;
}
var personFunc = person();
personFunc();
輸出:
//ergouzi

可以看到,這里即使person函數(shù)執(zhí)行完畢了,但是里面的name變量卻沒有被銷毀,這里再套用開頭解釋的概念,應(yīng)該能理解部分了吧。咱們再來驗證一下這種“被記憶的獨立變量”的特性

function person() {
  var name = 'ergouzi';
  var funcObj = {
    'nameFunc': function () {
      console.log(name);
    },
    'changeFunc': function () {
      name = 'goudanzi';
    }
  }
  return funcObj;
}
var funcObj = person();
funcObj.changeFunc();
funcObj.nameFunc();
輸出:
//goudanzi

可以看到,我們在該獨立變量的作用域外部改變了它的值,所以說明相同環(huán)境里創(chuàng)建的閉包函數(shù),引用的獨立變量為同一份拷貝,即同一個對象。其實用chrome調(diào)試一下就能很清楚的看到閉包函數(shù)長啥樣,比如我這里的閉包函數(shù)它長這樣(還長得挺漂亮的)


我們可以看到兩個函數(shù)“changeFunc”,“nameFunc”,從他們的Scopes里面都能找到Closure并且創(chuàng)建環(huán)境都為person,記憶的獨立變量都為“name”,

再來看點哦莫西羅伊的

for (var i = 0; i < 10; i++) {
  setTimeout(function(){
    console.log(i)
  }, 0);
}
輸出:
//10
//10
//10
//10
//10
//10
//10
//10
//10
//10
//簡要解釋一下輸出值,因為setTimeout是異步函數(shù),在i=0第一次循環(huán)時只是定義了第一個定時函數(shù)而并沒有執(zhí)行它,待到執(zhí)行第一個定時函數(shù),但此時i的值已經(jīng)變了

一個普通的for循環(huán),每次循環(huán)定義了一個定時器函數(shù),因為沒有給定時器函數(shù)的句柄傳參,它只能拿到i最后的值。我們換一種“閉包”一點的寫法

for (var i = 0; i < 10; i++) {
  setTimeout(((j) => console.log(j))(i), 0);
}
//或者這樣寫
for (var i = 0; i < 10; i++) {
  (j => setTimeout((j) => console.log(j), 0))(i);
}

這里用到了es6的箭頭函數(shù),想詳細(xì)了解箭頭函數(shù)請移步箭頭函數(shù)
這里的代碼將每次循環(huán)的i值傳給了一個閉包函數(shù),此時這個閉包函數(shù)記憶了這個i的值,等到執(zhí)行定時函數(shù)時,就可以正常打印出i值。

參考文檔https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures

//未完待續(xù),懶癌犯了剩下的下次補(bǔ)...
//接下來是每周最開心的游戲時間,仁王繼續(xù)落命中...
最后編輯于
?著作權(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ù)。

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

  • 閉包是自包含的函數(shù)代碼塊,可以在代碼中被傳遞和使用。Swift 中的閉包與 C 和 Objective-C 中的代...
    窮人家的孩紙閱讀 1,809評論 1 5
  • 本章將會介紹 閉包表達(dá)式尾隨閉包值捕獲閉包是引用類型逃逸閉包自動閉包枚舉語法使用Switch語句匹配枚舉值關(guān)聯(lián)值原...
    寒橋閱讀 1,628評論 0 3
  • 86.復(fù)合 Cases 共享相同代碼塊的多個switch 分支 分支可以合并, 寫在分支后用逗號分開。如果任何模式...
    無灃閱讀 1,551評論 1 5
  • 推開向湖的窗 三月的風(fēng)涌進(jìn)來 四月的雨打進(jìn)來 黑色的思念一直在窗外徘徊 湖面的波閃著行人的眼 湖底的潮低訴著生活的...
    海大寶閱讀 152評論 0 1
  • 中政公考(微信號:zzexam) 打造行業(yè)更高通過率 在公考筆試中無論是行測還申論,對于措辭的嚴(yán)謹(jǐn)性都有一定的要求...
    newbiefly閱讀 737評論 0 1

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