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

資訊專欄INFORMATION COLUMN

圖解作用域及閉包

shiyang6017 / 2097人閱讀

摘要:那其實閉包的原因就是外層函數(shù)的作用域?qū)ο鬅o法釋放其實就是一個函數(shù)調(diào)用會生成的臨時作用域圖中可看出其實就是在中的匿名函數(shù),所以他的就指向留下的作用域。

引言

網(wǎng)絡(luò)上關(guān)于作用域及閉包的文章很多,自己對于純理論知識并不能很快的理解,但自己對于圖畫有很強的記憶和理解能力,因此決定將此知識點以圖畫的知識表現(xiàn)出來,加深自身理解的同時如果能幫到正在學習的童鞋就再好不過了

下面我以函數(shù)的整個生命周期來訴說此部分知識

函數(shù)生命周期

先寫一下示例代碼

var a = 10;
function func(a) {
  var a = 20;
  a++;
  console.log(a);
}
func();
console.log(a);
開始執(zhí)行程序前

先創(chuàng)建 ECS,ECS 其實就是專門保存正在調(diào)用的函數(shù)的執(zhí)行環(huán)境的數(shù)組,也可以說對象,其實關(guān)聯(lián)數(shù)組也就相當于對象。

然后在 ECS 中添加瀏覽器主程序的執(zhí)行環(huán)境 main

創(chuàng)建全局作用域?qū)ο?window

main 執(zhí)行環(huán)境引用 window

定義函數(shù)時

原始類型的全局變量會直接存入 window 環(huán)境當中,因為函數(shù)是引用類型,所以首先用函數(shù)名聲明全局變量

然后創(chuàng)建函數(shù)對象,封裝函數(shù)定義

函數(shù)對象的 scope 屬性,指回函數(shù)創(chuàng)建時的作用域,意思是,函數(shù)執(zhí)行時如果函數(shù)本身提供的變量不能讓函數(shù)執(zhí)行完全,那它便會去回它創(chuàng)建時的那個作用域去尋找變量。

函數(shù)名后面存入指向函數(shù)對象的地址

引用類型在其中只能存儲地址,這個在此筆記談?wù)勚祩鬟f中有詳細說明

函數(shù)調(diào)用時

向 ECS 中壓入本次函數(shù)調(diào)用的執(zhí)行環(huán)境元素

創(chuàng)建本次函數(shù)調(diào)用時使用的函數(shù)作用域?qū)ο螅ˋO),也就是臨時作用域

在 AO 中創(chuàng)建儲存所有的局部變量,包括形參變量和函數(shù)內(nèi)用 var 聲明的變量

設(shè)置 AO 的 parent 屬性和引用函數(shù)的 scope 屬性指向父級作用域?qū)ο?/p>

函數(shù)的執(zhí)行環(huán)境引用 AO

順著那個箭頭,先在 AO 中找變量,也就是局部變量,如果 AO 中沒有,再順著箭頭去父級作用域中找

函數(shù)調(diào)用后

函數(shù)的執(zhí)行環(huán)境出棧,AO 釋放,AO 中的局部變量一同被釋放掉。

我們得知整個結(jié)果之后,自然而然那兩個 console 的結(jié)果也顯然意見。

閉包

前面我們提到過,全局變量是可重用但是污染全局,局部變量不會污染全局但是不可重用。

我自己認為閉包就是重用變量又保護變量不被污染的機制,就是為了解決這一情況而生的。

特點

包裹受保護的變量和操作變量的內(nèi)層函數(shù)的外層函數(shù)

外層函數(shù)要返回內(nèi)層函數(shù)的對象

return function(){..}

直接給全局變量賦值一個內(nèi)部 function

將內(nèi)部函數(shù)保存在一個對象的屬性或數(shù)組元素中 return [function function function]return {fun:function(){...}}

調(diào)用外層函數(shù),用外部變量接住返回的內(nèi)層函數(shù)對象,形成閉包。

原理

先貼出示例代碼

function outer() {
  var num = 1;
  return function() {
    console.log(num++);
  };
}

var getNum = outer();
getNum();
getNum();
num = 1;
getNum();

下面我把閉包形成的原理用畫圖工具畫出來

window 中存入 outer 名并指向 outer 函數(shù)對象,getNum 因為聲明提前也先將變量名存在 window 中。

getNum = outer() 其實包含 outer 的創(chuàng)建和 getNum 的賦值。

上面的圖畫的是 outer 函數(shù)進行到 var num = 1; ,前面都有說過,不過多重復(fù)。

創(chuàng)建了匿名函數(shù),getNum 指向了匿名函數(shù)對象,匿名對象的 scope 指向它的父級作用域,也就是 outer 的作用域,那這樣就形成了圖中的三角關(guān)系,此時 outer 執(zhí)行完畢,離開 ECS 執(zhí)行環(huán)境,outer 的 AO 本也應(yīng)該隨著離開,但是因為這強大的三角關(guān)系,強行拉住不讓其釋放,也就形成了所謂的閉包。

那其實閉包的原因就是:外層函數(shù)的作用域?qū)ο鬅o法釋放

getNum=outer()getNum 其實就是一個函數(shù)

調(diào)用getNum(),會生成 getNum 的臨時作用域,圖中可看出,getNum 其實就是在 outer 中的匿名函數(shù),所以他的 parent 就指向 outer 留下的作用域。當他執(zhí)行 console.log(num++) 的時候,在他的作用域中沒有 num 變量他就會順著作用域鏈去尋找,最終在 outer 中的作用域中找到 num 并對其進行自加操作。所以當下次調(diào)用 getNum 的時候 num 會從 2 開始,不會是一開始的 1

num 不是全局變量,還實現(xiàn)了 num 變量的重復(fù)調(diào)用。就達到了閉包的目的。

設(shè)置 num = 1 只是在 window 對象上添加存儲 num 的值,當下次調(diào)用 getNum 的時候 js 引擎還會從 getNum 作用域開始順著作用域鏈尋找 num,在 outerAO 就會尋找到 num,所以根本不會影響到 window 中的 num,也不會受其影響。因此此段代碼輸出的結(jié)果為 1 2 3

缺點

當然閉包也有其缺點

比普通函數(shù)占用更多內(nèi)存,因為外層函數(shù)的作用域?qū)ο螅ˋO)始終存在

容易造成內(nèi)存泄漏

解決辦法

將引用內(nèi)存函數(shù)對象的外部變量重置為 null

getNum = null;

getNum 指向 outer 函數(shù)對象的那根線就會斷掉,三角關(guān)系破裂,那函數(shù)對象和 outerAO 也會相繼被銷毀。

覺得文章不錯的話還請各位大佬給個 star 鼓勵一下 gayhub

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

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

相關(guān)文章

  • javascript系列--javascript深入淺出圖解作用域鏈和閉包

    摘要:變量對象也是有父作用域的。作用域鏈的頂端是全局對象。當函數(shù)被調(diào)用的時候,作用域鏈就會包含多個作用域?qū)ο蟆.敽瘮?shù)要訪問時,沒有找到,于是沿著作用域鏈向上查找,在的作用域找到了對應(yīng)的標示符,就會修改的值。 一、概要 對于閉包的定義(紅寶書P178):閉包就是指有權(quán)訪問另外一個函數(shù)的作用域中的變量的函數(shù)。 關(guān)鍵點: 1、閉包是一個函數(shù) 2、能夠訪問另外一個函數(shù)作用域中的變量 二、閉包特性 對...

    Jensen 評論0 收藏0
  • 結(jié)合作用域,執(zhí)行上下文圖解閉包

    摘要:作用域鏈所謂作用域鏈,是由當前環(huán)境與上層環(huán)境的一系列變量對象組成,它保證當前執(zhí)行環(huán)境對符合訪問權(quán)限的變量和函數(shù)的有序訪問。當我們在執(zhí)行函數(shù)的時候,需要的變量,在自己的作用域內(nèi)找不到,便會順著作用域鏈往上找,直到找到全局作用域。 一 作用域相關(guān)? ? ? 作用域是一套規(guī)則,用來管理引擎如何查找變量。在es5之前,js只有全局作用域及函數(shù)作用域。es6引入了塊級作用域。但是這個塊級別作用域...

    msup 評論0 收藏0
  • 淺談Javascript閉包作用域及內(nèi)存泄漏問題

    摘要:將作用域賦值給變量這里的作用域是,而不是將作用域賦值給一個變量閉包返回瀏覽器中內(nèi)存泄漏問題大家都知道,閉包會使變量駐留在內(nèi)存中,這也就導(dǎo)致了內(nèi)存泄漏。 上一章我們講了匿名函數(shù)和閉包,這次我們來談?wù)勯]包中作用域this的問題。 大家都知道,this對象是在運行時基于函數(shù)的執(zhí)行環(huán)境綁定的,如果this在全局就是[object window],如果在對象內(nèi)部就是指向這個對象,而閉包卻是在運行...

    source 評論0 收藏0
  • 《你不知道的JS》讀書筆記---作用域及閉包

    摘要:注此讀書筆記只記錄本人原先不太理解的內(nèi)容經(jīng)過閱讀你不知道的后的理解。作用域及閉包基礎(chǔ),代碼運行的幕后工作者引擎及編譯器。 注:此讀書筆記只記錄本人原先不太理解的內(nèi)容經(jīng)過閱讀《你不知道的JS》后的理解。 作用域及閉包基礎(chǔ),JS代碼運行的幕后工作者:引擎及編譯器。引擎負責JS程序的編譯及執(zhí)行,編譯器負責詞法分析和代碼生成。那么作用域就像一個容器,引擎及編譯器都從這里提取東西。 ...

    denson 評論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條評論

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