成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

理解js閉包

cnio / 3140人閱讀

摘要:總結(jié)閉包的核心是屬性,在函數(shù)解析過程中,如果函數(shù)引用了外層函數(shù)的變量,那么外層函數(shù)即使自身被銷毀的活動(dòng)對象帶著對應(yīng)變量將會被保留,并且記錄在屬性中,作為作用域鏈的第二層,如果還引用了外層函數(shù)的外層函數(shù)的變量,那么對應(yīng)的活動(dòng)對象與變量也會被保

總結(jié):閉包的核心是[[scope]]屬性,在函數(shù)解析過程中,如果函數(shù)引用了外層函數(shù)的變量,那么外層函數(shù)(即使自身被銷毀)的活動(dòng)對象帶著對應(yīng)變量將會被保留,并且記錄在scope屬性中,作為作用域鏈的第二層,如果還引用了外層函數(shù)的外層函數(shù)的變量,那么對應(yīng)的活動(dòng)對象與變量也會被保留,并記錄,將會作為作用域鏈的第三層,依次類推...。當(dāng)函數(shù)被調(diào)用時(shí),所取到的外部變量的值將會是調(diào)用時(shí)各個(gè)變量的值。即當(dāng)前值。

閉包調(diào)用時(shí)也是普通函數(shù),只不過作用域鏈多了閉包Closure的成分

閉包的用途:1.模仿塊級作用域,在立即調(diào)用函數(shù)中聲明內(nèi)部需要使用的變量;2.管理私有變量和方法;3.函數(shù)柯里化

來個(gè)極端的例子

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}
        // 函數(shù)在這里立即調(diào)用
        // i為實(shí)時(shí)值0,1,2,3...
        closureCallback()
    }
    return result
}


從圖中可以看到,最終返回結(jié)果分別引用了closureCallback, outer,closure中的變量,所以,在作用域鏈中會保存這三個(gè)函數(shù)的活動(dòng)對象,不同時(shí)間調(diào)用,返回的count值不同,說明引用的是當(dāng)前值。
以下是手工示意圖

以下是我的學(xué)習(xí)過程
JavaScript里面的閉包,指的是函數(shù)與聲明該函數(shù)的詞法環(huán)境的組合。
一般在函數(shù)里面聲明函數(shù),并且引用外面函數(shù)的變量,就會產(chǎn)生閉包。定義在全局的時(shí)候,默認(rèn)不產(chǎn)生閉包(所謂閉包,就是當(dāng)內(nèi)部函數(shù)引用了外部函數(shù)中的變量時(shí),會在函數(shù)的作用域上面添加一層,這一層包含了函數(shù)所引用的外部函數(shù)的變量,存放在scope屬性里面,在調(diào)用時(shí),用于形成作用域鏈)
函數(shù)在執(zhí)行時(shí),會在內(nèi)存中創(chuàng)建一個(gè)活動(dòng)對象,該活動(dòng)對象包含arguments以及一些參數(shù)。并通過復(fù)制[[scope]]屬性中的對象構(gòu)建起執(zhí)行環(huán)境的作用域鏈。

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()

主要體現(xiàn)在函數(shù)返回函數(shù),函數(shù)A在調(diào)用函數(shù)B時(shí)被創(chuàng)建并從B函數(shù)的內(nèi)部返回。當(dāng)我們調(diào)用A函數(shù)的時(shí)候,B函數(shù)的作用域鏈已經(jīng)從內(nèi)存中銷毀,但是我們?nèi)匀豢梢栽贏中訪問B中存在的變量。因?yàn)锽中的變量仍然保存在A的活動(dòng)對象中(作用域鏈中[[scope]]對象里面)
此時(shí),函數(shù)A與A的scope構(gòu)成closure函數(shù)的閉包實(shí)例


從圖中可以看到,ar[0](以下稱為函數(shù)A)函數(shù)的作用域鏈最頂層為自身活動(dòng)對象(arguments, caller, length, name等等構(gòu)成)再往上則是由一個(gè)Closure對象實(shí)例構(gòu)成,可以看到這一層里面只包含一個(gè)變量i,即創(chuàng)建A時(shí)外層函數(shù)里面聲明的變量i。當(dāng)我們調(diào)用A時(shí),我們在第二層作用域鏈上面找到的這個(gè)i變量。
為什么arr數(shù)組每一項(xiàng)都返回的是10,而不是對應(yīng)的下標(biāo)值的原因就在這里:當(dāng)我們調(diào)用數(shù)組項(xiàng)函數(shù)時(shí),遇到變量i,并且在第二層作用域鏈讀取到i,這里面保存的i就是closure函數(shù)里面定義的i。在A調(diào)用時(shí),closure已經(jīng)執(zhí)完畢,在closure執(zhí)行的過程中i的值從0變到了10。這個(gè)性質(zhì)類似于把原本存在于closure函數(shù)中的變量,在closure函數(shù)執(zhí)行完畢后(從內(nèi)存中移除)我們可以在A自身的scope屬性里訪問到。
簡單一點(diǎn)說就是我們在調(diào)用A函數(shù)的時(shí)候,訪問到的i變量,是函數(shù)closure(雖然它不在了但是它的變量還在,仍然被scope屬性引用。)的當(dāng)前值(實(shí)時(shí)值)

所以要達(dá)到預(yù)期目標(biāo),我們只需要保證它的scope對象中保存的這個(gè)‘i’值是正確的就可以了。
這里面的思路就是,函數(shù)A被當(dāng)做普通函數(shù)調(diào)用時(shí),非閉包情況下,作用域就是自身(沒有i變量)+ 全局作用域(也沒有),所以這里還是需要借助閉包。即需要保證A上一層作用域的i是正確的值

1.創(chuàng)建另外一個(gè)閉包,每個(gè)i的值都會創(chuàng)建一個(gè)閉包

function closureCallback(i) {
    // 返回函數(shù)里面的i變量就是closureCallback函數(shù)的參數(shù)i
    return function() {
        return i
    }
}

function closure() {
    let result = [], b = "closure"
    for (var i=0; i<10; i++) {
                // 這里的closureCallback作為普通函數(shù)調(diào)用
                // 且沒有引用closure函數(shù)的變量,
                // 函數(shù)作用域內(nèi)的變量,無法直接在函數(shù)外取得
                // 所以作用域鏈不包含closure
                // 所以在closureCallback函數(shù)[[scope]]中不會有closure函數(shù)
        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()

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/92836.html

相關(guān)文章

  • 談?wù)勎宜?em>理解的閉包,js、php、golang里的closure

    摘要:當(dāng)初看這個(gè)解釋有點(diǎn)懵逼,理解成閉包就是函數(shù)中的函數(shù)了。里的閉包最近不滿足于只干前端的活,開始用起了。里的閉包最近在學(xué)習(xí)語言,讓我們來看一下語言里的閉包。在中,閉包特指將函數(shù)作為值返回的情況,被返回的函數(shù)引用了生成它的母函數(shù)中的變量。 本人開始接觸編程是從js開始的,當(dāng)時(shí)網(wǎng)上很多人說閉包是難點(diǎn),各種地方對閉包的解釋也是千奇百怪。如今開始接觸js以外的各種編程語言,發(fā)現(xiàn)不光是js,php、...

    betacat 評論0 收藏0
  • 談?wù)勎宜?em>理解的閉包js、php、golang里的closure

    摘要:當(dāng)初看這個(gè)解釋有點(diǎn)懵逼,理解成閉包就是函數(shù)中的函數(shù)了。里的閉包最近不滿足于只干前端的活,開始用起了。里的閉包最近在學(xué)習(xí)語言,讓我們來看一下語言里的閉包。在中,閉包特指將函數(shù)作為值返回的情況,被返回的函數(shù)引用了生成它的母函數(shù)中的變量。 本人開始接觸編程是從js開始的,當(dāng)時(shí)網(wǎng)上很多人說閉包是難點(diǎn),各種地方對閉包的解釋也是千奇百怪。如今開始接觸js以外的各種編程語言,發(fā)現(xiàn)不光是js,php、...

    zhoutao 評論0 收藏0
  • js閉包理解

    摘要:一般來講,函數(shù)執(zhí)行完畢后,局部活動(dòng)對象就會被銷毀,內(nèi)存中僅保存全局作用域,但是閉包的情況有所不同理解閉包的前提先理解另外兩個(gè)內(nèi)容作用域鏈垃圾回收作用域鏈當(dāng)代碼在執(zhí)行過程中,會創(chuàng)建變量對象的一個(gè)作用域鏈。 閉包是javascript語言的一個(gè)難點(diǎn),也是它的特色,很多高級應(yīng)用都要依靠閉包來實(shí)現(xiàn)。個(gè)人的理解是:函數(shù)中嵌套函數(shù)。 閉包的定義及其優(yōu)缺點(diǎn) 閉包是指有權(quán)訪問另一個(gè)函數(shù)作用域中的變量的...

    EasonTyler 評論0 收藏0
  • 理解 JavaScript 閉包

    摘要:如何在初學(xué)就理解閉包你需要接著讀下去。這樣定義閉包是函數(shù)和聲明該函數(shù)的詞法環(huán)境的組合。小結(jié)閉包在中隨處可見。閉包是中的精華部分,理解它需要具備一定的作用域執(zhí)行棧的知識。 這是本系列的第 4 篇文章。 作為 JS 初學(xué)者,第一次接觸閉包的概念是因?yàn)閷懗隽祟愃葡旅娴拇a: for (var i = 0; i < helpText.length; i++) { var item = he...

    寵來也 評論0 收藏0
  • JavaScript中的閉包

    摘要:閉包引起的內(nèi)存泄漏總結(jié)從理論的角度將由于作用域鏈的特性中所有函數(shù)都是閉包但是從應(yīng)用的角度來說只有當(dāng)函數(shù)以返回值返回或者當(dāng)函數(shù)以參數(shù)形式使用或者當(dāng)函數(shù)中自由變量在函數(shù)外被引用時(shí)才能成為明確意義上的閉包。 文章同步到github js的閉包概念幾乎是任何面試官都會問的問題,最近把閉包這塊的概念梳理了一下,記錄成以下文章。 什么是閉包 我先列出一些官方及經(jīng)典書籍等書中給出的概念,這些概念雖然...

    HmyBmny 評論0 收藏0
  • js 變量提升和閉包理解

    摘要:變量的作用域無非就是兩種全局變量和局部變量。其中內(nèi)部函數(shù)中可以訪問外部函數(shù)的變量,是因?yàn)閮?nèi)部函數(shù)的作用域鏈中包含了外部函數(shù)的作用域也可以理解為內(nèi)部函數(shù)的作用范圍輻射到了外部函數(shù)的作用范圍另一方面,在函數(shù)外部自然無法讀取函數(shù)內(nèi)的局部變量。 以前學(xué)習(xí)的時(shí)候,了解過變量提升和閉包,但是沒有深入了解,網(wǎng)上查了資料,這里記錄下,只供參考。部分內(nèi)容引用: https://www.cnblogs.c...

    luoyibu 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<