成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

詳解js中的閉包

chaosx110 / 449人閱讀

摘要:定義函數(shù)的時候,為什么的值重新從開始了因?yàn)橛忠淮芜\(yùn)行了函數(shù),生成一個新的的活動對象,所以的作用域鏈引用的是一個新的值。

前言

在js中,閉包是一個很重要又相當(dāng)不容易完全理解的要點(diǎn),網(wǎng)上關(guān)于講解閉包的文章非常多,但是并不是非常容易讀懂,在這里以《javascript高級程序設(shè)計》里面的理論為基礎(chǔ)。用拆分的方式,深入講解一下對于閉包的理解,如果有不對請指正。

寫在閉包之前

閉包的內(nèi)部細(xì)節(jié),依賴于函數(shù)被調(diào)用過程所發(fā)生的一系列事件為基礎(chǔ),所以有必要先弄清楚以下幾個概念:

1. 執(zhí)行環(huán)境和活動對象

- 執(zhí)行環(huán)境(execution context)定義了變量或者函數(shù)有權(quán)訪問的其他數(shù)據(jù),每個執(zhí)行環(huán)境都有一個與之關(guān)聯(lián)的變量對象(variable object),執(zhí)行環(huán)境中定義的變量和函數(shù)就保存在這個變量對象中;
全局執(zhí)行環(huán)境是最外圍的一個執(zhí)行環(huán)境,通常被認(rèn)為是window對象
執(zhí)行環(huán)境和變量對象在運(yùn)行函數(shù)時生成
執(zhí)行環(huán)境中的所有代碼執(zhí)行完以后,執(zhí)行環(huán)境被銷毀,保存在其中的變量和函數(shù)也隨之銷毀;(全局執(zhí)行環(huán)境到應(yīng)用退出時銷毀)

2. 作用域鏈

當(dāng)代碼在一個執(zhí)行環(huán)境中執(zhí)行時,會創(chuàng)建變量對象的一個作用域鏈(scope chain),作用域鏈用來指定執(zhí)行環(huán)境有權(quán)訪問的所有變量和函數(shù)的訪問順序;
作用域鏈的最前端,始終是當(dāng)前代碼執(zhí)行環(huán)境的變量對象,如果這個環(huán)境是函數(shù),則其活動對象就是變量對象
作用域鏈的下一個變量對象,來自外部包含環(huán)境,再下一個變量對象,來自下一個外部包含環(huán)境,以此類推直到全局執(zhí)行環(huán)境
在函數(shù)執(zhí)行過程,根據(jù)當(dāng)前執(zhí)行環(huán)境的作用域鏈來逐層向外查找變量,并且進(jìn)行標(biāo)識符解析

是不是覺得以上的理論很枯燥而且艱澀?因?yàn)榛旧鲜菑臅弦脕淼?,不著急著理解,先擺在上面,等會結(jié)合案例回頭再來看!接下來請看樣例:

樣例1

以這段簡單的代碼為例,根據(jù)上面的理論畫一下關(guān)系圖(直接用ps畫的,原諒我拙劣的筆跡):

如圖所示,在執(zhí)行函數(shù)A的時候,創(chuàng)建了A的執(zhí)行環(huán)境和變量對象,其中A的變量對象和全局變量對象中都含有a變量,根據(jù)作用域鏈從前向后查找,在A的變量對象中找到,所以輸出1,執(zhí)行完畢以后 ,A的執(zhí)行環(huán)境銷毀,A的變量對象由于沒有被引用,所以也銷毀;

樣例2
     

這個例子比較簡單,要畫圖的話只需要畫一個全局變量對即可,因?yàn)樵趈s中,外圍環(huán)境無法訪問內(nèi)圍局部變量(其實(shí)本質(zhì)就是作用域鏈上找不到相應(yīng)的值),所以這里會報變量未定義的錯誤。

樣例3
  

上面這個例子,在函數(shù)A中定義了函數(shù)B,關(guān)系圖如下:
從圖上可以很清楚的看出,在每個執(zhí)行環(huán)境中可以訪問到的變量對象,所以B可以訪問A的變量對象和全局變量對象中的變量以及自身變量對象,A可以訪問自身變量對象和全局變量對象

關(guān)于執(zhí)行環(huán)境和作用域鏈暫時說到這里,下面進(jìn)入正題,講閉包;

初涉閉包

閉包是指有權(quán)訪問另一個函數(shù)作用域變量的函數(shù),創(chuàng)建閉包的通常方式,是在一個函數(shù)內(nèi)部創(chuàng)建另一個函數(shù)

上文我們提到了,由于作用域鏈的結(jié)構(gòu),外圍函數(shù)是無法訪問內(nèi)部變量的,為了能夠訪問內(nèi)部變量,我們就可以使用閉包,閉包的本質(zhì)還是函數(shù),閉包的本質(zhì)還是函數(shù)閉包的本質(zhì)還是函數(shù)。

樣例4

上面就是一個很簡單的閉包例子,通過m函數(shù),我們可以獲得A函數(shù)內(nèi)部變量的值,這個樣例比較簡單,看不出什么問題,接下來我們來深入了解一下。
-------------------------------從簡單到復(fù)雜的分割線,請做好準(zhǔn)備----------------------------------------------------

閉包詳解 難點(diǎn)一:判斷作用域指向的變量對象是否相同
樣例5

上面這個例子其實(shí)可以引出幾個問題:
1.為什么連續(xù)執(zhí)行m1的時候,x的值在遞增?
2.定義函數(shù)m2的時候,為什么x的值重新從1開始了?
3.運(yùn)行m2以后,為什么再運(yùn)行m1,x還是按照之前m1的運(yùn)行結(jié)果繼續(xù)增長?(其實(shí)就是m1和m2里面的x為什么是相互獨(dú)立,各自維持的?)

其實(shí)要解決上面的問題,我們就要用到前面鋪墊的知識點(diǎn)了:
首先,先畫一下結(jié)構(gòu)圖,
(額,這圖畫的可能真的有點(diǎn)丑),不要慌,圖上雖然畫的有點(diǎn)亂,但是其實(shí)很簡單:左半部分和上面簡單閉包的例子,其實(shí)是完全一樣的,而右邊半部分,與左邊其實(shí)是完全對稱的;注意看圖上的重點(diǎn):每次執(zhí)行A函數(shù)時,都會生成一個A的活動變量和執(zhí)行環(huán)境,執(zhí)行完畢以后,A的執(zhí)行環(huán)境銷毀,但是活動對象由于被閉包函數(shù)引用,所以仍然保留,所以,最終剩下兩個A的變量對象,因此m1和m2在操作x時,指向的是不同的數(shù)據(jù),

現(xiàn)在來回答上面的三個問題:
1.(為什么連續(xù)執(zhí)行m1的時候,x的值在遞增?)
answer:因?yàn)閙1在引用的活動對象A一直沒有釋放(想釋放的話可以讓m1=null),所以x的值一直遞增。
2.定義函數(shù)m2的時候,為什么x的值重新從1開始了?
answer:因?yàn)橛忠淮芜\(yùn)行了A函數(shù),生成一個新的A的活動對象,所以m2的作用域鏈引用的是一個新的x值。
3.m1和m2里面的x為什么是相互獨(dú)立,各自維持的?
answer:因?yàn)樵诙xm1和m2的時候,分別運(yùn)行了A函數(shù),生成了兩個活動對象,所以,m1和m2的作用域鏈?zhǔn)侵赶虿煌腁的活動對象的。

好的,到這里先回顧一下前面說到的知識點(diǎn):

執(zhí)行環(huán)境和變量對象在運(yùn)行函數(shù)時生成
執(zhí)行環(huán)境中的所有代碼執(zhí)行完以后,執(zhí)行環(huán)境被銷毀,保存在其中的變量和函數(shù)也隨之銷毀;(全局執(zhí)行環(huán)境到應(yīng)用退出時銷毀)

感覺理解了嗎?接下來,再看看另一個很類似的例子:

樣例6
 

這個例子和剛剛十分類似,不同的是,在A內(nèi)部就先定義了兩個函數(shù),可以看出 ,最后的結(jié)果與上面的例子有些不同:
變量x仍然能保持遞增,但是m[0]和m[1]定義的函數(shù),對于x的改變不再是相互獨(dú)立的,其實(shí)大家估計猜到了,這里的m[0]和m[1]的作用域指向的A的變量對象,其實(shí)是同一個,為什么呢?很簡單,看看剛剛這段代碼,其實(shí)是只調(diào)用了一次A函數(shù),再看上文那句話:

執(zhí)行環(huán)境和變量對象在運(yùn)行函數(shù)時生成

既然A只執(zhí)行一次,那么A的活動變量當(dāng)然也就生成了一個,所以這里m[0]和m[1]的作用域指向同一個A的變量對象

難點(diǎn)二:判斷變量對象中變量的值
 樣例7
 

這個例子其實(shí)算是一個經(jīng)典案例,在很多地方都有提到,執(zhí)行完畢后 funs數(shù)組中,funs[0]-funs[9]存的其實(shí)都是一樣的,都是一個返回i值的函數(shù),這個例子容易錯誤的地方其實(shí)在于,弄錯了產(chǎn)生執(zhí)行環(huán)境的時機(jī),還是看這句話:

執(zhí)行環(huán)境和變量對象在運(yùn)行函數(shù)時生成

所以,當(dāng)執(zhí)行 var funs = A();時,只是定義函數(shù),而沒有執(zhí)行,真正產(chǎn)生環(huán)境變量的時間是在console.log(funs[0]());這三句的時候,此時A的變量對象中i值是什么呢?很簡單,看它return的時候,i的值,顯然,i的值是10,所以,最后三句輸出的都是10

好的,針對以上的案例,如果我就是想讓fun[i]能夠返回i,那應(yīng)該怎么寫呢?在《javascript高級程序設(shè)計》中,提供了一種參考的寫法:

 樣例8
 

是不是一看頭就大了?沒關(guān)系,接下來我們慢慢分析,當(dāng)然,上述代碼中anonymous1和anonymous2兩個名字是我自己添加上的,為了后面能夠更好的說明。
首先,先來看看function anonymous1(num){}(i),這是一個立即執(zhí)行函數(shù),效果和名字一樣,定義完之后馬上運(yùn)行結(jié)果,那這里運(yùn)行的結(jié)果是什么呢?就是把i的值立即傳遞給num這個局部變量,然后再返回anonymous2,請注意這個立即執(zhí)行函數(shù)被執(zhí)行的次數(shù),10次,再來看看這句話

執(zhí)行環(huán)境和變量對象在運(yùn)行函數(shù)時生成

好的,那現(xiàn)在請回答我:
這里面生成了幾個anonymous1的活動變量?
answer:當(dāng)然也是10個,
那每個anonymous1活動變量中存貯的num值是多少?
answer:看anonymous函數(shù)return的時候可以知道,存貯的num值就是每次傳入的i值,也就是0-9

好了,那現(xiàn)在很明了了,這樣的寫法其實(shí)相當(dāng)于,把每次的i值都保存在一個anonymous1活動變量鐘,給最內(nèi)層的anonymous2函數(shù)使用

小結(jié)

寫到這里,關(guān)于閉包的主要特征和辨別方式已經(jīng)基本講到了,個人感覺因?yàn)檫@個問題比較抽象,還是多看看文中以及網(wǎng)上的一些例子,加深理解。以上內(nèi)容屬于個人見解,如果有不同意見,歡迎指出和探討。希望能對看到的人有所幫助,同時,碼字不易(尤其是還要配上靈魂畫師級別的配圖~),請尊重作者的版權(quán),轉(zhuǎn)載請注明出處,如作商用,請與作者聯(lián)系,感謝!

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

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/80770.html

相關(guān)文章

  • 詳解js閉包

    摘要:但閉包的情況不同嵌套函數(shù)的閉包執(zhí)行后,,然后還在被回收閉包會使變量始終保存在內(nèi)存中,如果不當(dāng)使用會增大內(nèi)存消耗。每個函數(shù),不論多深,都可以認(rèn)為是全局的子作用域,可以理解為閉包。 閉包(closure)是Javascript語言的一個難點(diǎn),也是它的特色,很多高級應(yīng)用都要依靠閉包實(shí)現(xiàn)。 閉包的特性 閉包有三個特性: 1.函數(shù)嵌套函數(shù) 2.函數(shù)內(nèi)部可以引用外部的參數(shù)和變量 3.參數(shù)和變量不會...

    Chiclaim 評論0 收藏0
  • JavaScript深入淺出

    摘要:理解的函數(shù)基礎(chǔ)要搞好深入淺出原型使用原型模型,雖然這經(jīng)常被當(dāng)作缺點(diǎn)提及,但是只要善于運(yùn)用,其實(shí)基于原型的繼承模型比傳統(tǒng)的類繼承還要強(qiáng)大。中文指南基本操作指南二繼續(xù)熟悉的幾對方法,包括,,。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。 怎樣使用 this 因?yàn)楸救藢儆趥吻岸?,因此文中只看懂?8 成左右,希望能夠給大家?guī)韼椭?...(據(jù)說是阿里的前端妹子寫的) this 的值到底...

    blair 評論0 收藏0
  • JavaScript 中 閉包詳解

    摘要:局部變量,當(dāng)定義該變量的函數(shù)調(diào)用結(jié)束時,該變量就會被垃圾回收機(jī)制回收而銷毀。如果在函數(shù)中不使用匿名函數(shù)創(chuàng)建閉包,而是通過引用一個外部函數(shù),也不會出現(xiàn)循環(huán)引用的問題。 閉包是什么 在 JavaScript 中,閉包是一個讓人很難弄懂的概念。ECMAScript 中給閉包的定義是:閉包,指的是詞法表示包括不被計算的變量的函數(shù),也就是說,函數(shù)可以使用函數(shù)之外定義的變量。 是不是看完這個定義感...

    longshengwang 評論0 收藏0
  • JS閉包與this詳解

    摘要:刪除對匿名函數(shù)的引用,以便釋放內(nèi)存在匿名函數(shù)從中被返回后,它的作用域鏈被初始化為包含函數(shù)的活動對象和全局變量對象。閉包與變量我們要注意到,閉包只能取到任意變量的最后值,也就是我們保存的是活動對象,而不是確定值。 工作中會遇到很多 this對象 指向不明的問題,你可能不止一次用過 _self = this 的寫法來傳遞this對象,它每每會讓我們覺得困惑和抓狂,我們很可能會好奇其中到底發(fā)...

    fireflow 評論0 收藏0
  • 詳解js變量、作用域及內(nèi)存

    摘要:不是引用類型,無法輸出簡而言之,堆內(nèi)存存放引用值,棧內(nèi)存存放固定類型值。變量的查詢在變量的查詢中,訪問局部變量要比全局變量來得快,因此不需要向上搜索作用域鏈。 贊助我以寫出更好的文章,give me a cup of coffee? 2017最新最全前端面試題 基本類型值有:undefined,NUll,Boolean,Number和String,這些類型分別在內(nèi)存中占有固定的大小空...

    waltr 評論0 收藏0

發(fā)表評論

0條評論

chaosx110

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<