摘要:總結閉包的核心是屬性,在函數解析過程中,如果函數引用了外層函數的變量,那么外層函數即使自身被銷毀的活動對象帶著對應變量將會被保留,并且記錄在屬性中,作為作用域鏈的第二層,如果還引用了外層函數的外層函數的變量,那么對應的活動對象與變量也會被保
總結:閉包的核心是[[scope]]屬性,在函數解析過程中,如果函數引用了外層函數的變量,那么外層函數(即使自身被銷毀)的活動對象帶著對應變量將會被保留,并且記錄在scope屬性中,作為作用域鏈的第二層,如果還引用了外層函數的外層函數的變量,那么對應的活動對象與變量也會被保留,并記錄,將會作為作用域鏈的第三層,依次類推...。當函數被調用時,所取到的外部變量的值將會是調用時各個變量的值。即當前值。閉包調用時也是普通函數,只不過作用域鏈多了閉包Closure的成分
閉包的用途:1.模仿塊級作用域,在立即調用函數中聲明內部需要使用的變量;2.管理私有變量和方法;3.函數柯里化
來個極端的例子
function closure() { let result = [], count = 1 setInterval(() => {count++}, 1000) function outer() { let doufu = "wu" return function inner() { let foo = "foo" return function closureCallback() { let bar = {bar: "bar"}, bar1 = "bar" result[i] = function () { console.log(count) let b = doufu return bar.bar + i } } } } let inner = outer() let closureCallback = inner() for (var i=0; i<10; i++) { // [[scope]]包含closure{result, i} // 函數在這里立即調用 // i為實時值0,1,2,3... closureCallback() } return result }
從圖中可以看到,最終返回結果分別引用了closureCallback, outer,closure中的變量,所以,在作用域鏈中會保存這三個函數的活動對象,不同時間調用,返回的count值不同,說明引用的是當前值。
以下是手工示意圖
以下是我的學習過程
JavaScript里面的閉包,指的是函數與聲明該函數的詞法環境的組合。
一般在函數里面聲明函數,并且引用外面函數的變量,就會產生閉包。定義在全局的時候,默認不產生閉包(所謂閉包,就是當內部函數引用了外部函數中的變量時,會在函數的作用域上面添加一層,這一層包含了函數所引用的外部函數的變量,存放在scope屬性里面,在調用時,用于形成作用域鏈)
函數在執行時,會在內存中創建一個活動對象,該活動對象包含arguments以及一些參數。并通過復制[[scope]]屬性中的對象構建起執行環境的作用域鏈。
var bar = "zoo" function Foo() { this.bar = bar }
function foo() { let bar = "zoo" function zoo() { let zoo = bar } } foo()
function closure() { let result = [] for (var i=0; i<10; i++) { result[i] = function () { return i } } return result } let arr = closure()
主要體現在函數返回函數,函數A在調用函數B時被創建并從B函數的內部返回。當我們調用A函數的時候,B函數的作用域鏈已經從內存中銷毀,但是我們仍然可以在A中訪問B中存在的變量。因為B中的變量仍然保存在A的活動對象中(作用域鏈中[[scope]]對象里面)
此時,函數A與A的scope構成closure函數的閉包實例
從圖中可以看到,ar[0](以下稱為函數A)函數的作用域鏈最頂層為自身活動對象(arguments, caller, length, name等等構成)再往上則是由一個Closure對象實例構成,可以看到這一層里面只包含一個變量i,即創建A時外層函數里面聲明的變量i。當我們調用A時,我們在第二層作用域鏈上面找到的這個i變量。
為什么arr數組每一項都返回的是10,而不是對應的下標值的原因就在這里:當我們調用數組項函數時,遇到變量i,并且在第二層作用域鏈讀取到i,這里面保存的i就是closure函數里面定義的i。在A調用時,closure已經執完畢,在closure執行的過程中i的值從0變到了10。這個性質類似于把原本存在于closure函數中的變量,在closure函數執行完畢后(從內存中移除)我們可以在A自身的scope屬性里訪問到。
簡單一點說就是我們在調用A函數的時候,訪問到的i變量,是函數closure(雖然它不在了但是它的變量還在,仍然被scope屬性引用。)的當前值(實時值)
所以要達到預期目標,我們只需要保證它的scope對象中保存的這個‘i’值是正確的就可以了。
這里面的思路就是,函數A被當做普通函數調用時,非閉包情況下,作用域就是自身(沒有i變量)+ 全局作用域(也沒有),所以這里還是需要借助閉包。即需要保證A上一層作用域的i是正確的值
1.創建另外一個閉包,每個i的值都會創建一個閉包
function closureCallback(i) { // 返回函數里面的i變量就是closureCallback函數的參數i return function() { return i } } function closure() { let result = [], b = "closure" for (var i=0; i<10; i++) { // 這里的closureCallback作為普通函數調用 // 且沒有引用closure函數的變量, // 函數作用域內的變量,無法直接在函數外取得 // 所以作用域鏈不包含closure // 所以在closureCallback函數[[scope]]中不會有closure函數 result[i] = closureCallback(i) } return result }
2.使用匿名閉包
function closure() { let result = [], b = "closure" for (var i=0; i<10; i++) { result[i] = (function (i) { return () => i })(i) } return result } let arr = closure()
3.使用let,減少閉包,let具有塊級作用域的效果
function closure() { let result = [], b = "closure" for (var i=0; i<10; i++) { let j = i result[i] = function () { return j } } return result } let arr = closure()
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/92836.html
摘要:當初看這個解釋有點懵逼,理解成閉包就是函數中的函數了。里的閉包最近不滿足于只干前端的活,開始用起了。里的閉包最近在學習語言,讓我們來看一下語言里的閉包。在中,閉包特指將函數作為值返回的情況,被返回的函數引用了生成它的母函數中的變量。 本人開始接觸編程是從js開始的,當時網上很多人說閉包是難點,各種地方對閉包的解釋也是千奇百怪。如今開始接觸js以外的各種編程語言,發現不光是js,php、...
摘要:當初看這個解釋有點懵逼,理解成閉包就是函數中的函數了。里的閉包最近不滿足于只干前端的活,開始用起了。里的閉包最近在學習語言,讓我們來看一下語言里的閉包。在中,閉包特指將函數作為值返回的情況,被返回的函數引用了生成它的母函數中的變量。 本人開始接觸編程是從js開始的,當時網上很多人說閉包是難點,各種地方對閉包的解釋也是千奇百怪。如今開始接觸js以外的各種編程語言,發現不光是js,php、...
摘要:一般來講,函數執行完畢后,局部活動對象就會被銷毀,內存中僅保存全局作用域,但是閉包的情況有所不同理解閉包的前提先理解另外兩個內容作用域鏈垃圾回收作用域鏈當代碼在執行過程中,會創建變量對象的一個作用域鏈。 閉包是javascript語言的一個難點,也是它的特色,很多高級應用都要依靠閉包來實現。個人的理解是:函數中嵌套函數。 閉包的定義及其優缺點 閉包是指有權訪問另一個函數作用域中的變量的...
摘要:如何在初學就理解閉包你需要接著讀下去。這樣定義閉包是函數和聲明該函數的詞法環境的組合。小結閉包在中隨處可見。閉包是中的精華部分,理解它需要具備一定的作用域執行棧的知識。 這是本系列的第 4 篇文章。 作為 JS 初學者,第一次接觸閉包的概念是因為寫出了類似下面的代碼: for (var i = 0; i < helpText.length; i++) { var item = he...
摘要:閉包引起的內存泄漏總結從理論的角度將由于作用域鏈的特性中所有函數都是閉包但是從應用的角度來說只有當函數以返回值返回或者當函數以參數形式使用或者當函數中自由變量在函數外被引用時才能成為明確意義上的閉包。 文章同步到github js的閉包概念幾乎是任何面試官都會問的問題,最近把閉包這塊的概念梳理了一下,記錄成以下文章。 什么是閉包 我先列出一些官方及經典書籍等書中給出的概念,這些概念雖然...
摘要:變量的作用域無非就是兩種全局變量和局部變量。其中內部函數中可以訪問外部函數的變量,是因為內部函數的作用域鏈中包含了外部函數的作用域也可以理解為內部函數的作用范圍輻射到了外部函數的作用范圍另一方面,在函數外部自然無法讀取函數內的局部變量。 以前學習的時候,了解過變量提升和閉包,但是沒有深入了解,網上查了資料,這里記錄下,只供參考。部分內容引用: https://www.cnblogs.c...
閱讀 1882·2021-11-11 16:55
閱讀 2064·2021-10-08 10:13
閱讀 739·2019-08-30 11:01
閱讀 2155·2019-08-29 13:19
閱讀 3277·2019-08-28 18:18
閱讀 2620·2019-08-26 13:26
閱讀 579·2019-08-26 11:40
閱讀 1864·2019-08-23 17:17