深入理解閉包系列第二篇——從執行環境角度看閉包

前面的話

  本文從執行環境的角度來分析閉包,先用一張圖開宗明義,然后根據圖示內容對代碼進行逐行說明,試圖對閉包進行更直觀的解釋

?

圖示

?

說明

  下面按照代碼執行流的順序對該圖示進行詳細說明

function foo(){var a = 2;function bar(){console.log(a);}return bar;
}
var baz = foo();
baz();

  【1】代碼執行流進入全局執行環境,并對全局執行環境中的代碼進行聲明提升(hoisting)

  【2】執行流執行第9行代碼var baz = foo();,調用foo()函數,此時執行流進入foo()函數執行環境中,對該執行環境中的代碼進行聲明提升過程。此時執行環境棧中存在兩個執行環境,foo()函數為當前執行流所在執行環境

  【3】執行流執行第2行代碼var a = 2;,對a進行LHS查詢,給a賦值2

  【4】執行流執行第7行代碼return bar;,將bar()函數作為返回值返回。按理說,這時foo()函數已經執行完畢,應該銷毀其執行環境,等待垃圾回收。但因為其返回值是bar函數。bar函數中存在自由變量a,需要通過作用域鏈到foo()函數的執行環境中找到變量a的值,所以雖然foo函數的執行環境被銷毀了,但其變量對象不能被銷毀,只是從活動狀態變成非活動狀態;而全局執行環境的變量對象則變成活動狀態;執行流繼續執行第9行代碼var baz = foo();,把foo()函數的返回值bar函數賦值給baz

  【5】執行流執行第10行代碼baz();,通過在全局執行環境中查找baz的值,baz保存著foo()函數的返回值bar。所以這時執行baz(),會調用bar()函數,此時執行流進入bar()函數執行環境中,對該執行環境中的代碼進行聲明提升過程。此時執行環境棧中存在三個執行環境,bar()函數為當前執行流所在執行環境

  在聲明提升的過程中,由于a是個自由變量,需要通過bar()函數的作用域鏈bar() -> foo() -> 全局作用域進行查找,最終在foo()函數中也就是代碼第2行找到var a = 2;,然后在foo()函數的執行環境中找到a的值是2,所以給a賦值2

  【6】執行流執行第5行代碼console.log(a);,調用內部對象console,并從console對象中log方法,將a作為參數傳遞進入。從bar()函數的執行環境中找到a的值是2,所以,最終在控制臺顯示2

  【7】執行流執行第6行代碼},bar()的執行環境被彈出執行環境棧,并被銷毀,等待垃圾回收,控制權交還給全局執行環境

  【8】當頁面關閉時,所有的執行環境都被銷毀

?

總結

  從上述說明的第5步可以看出,由于閉包bar()函數的原因,雖然foo()函數的執行環境銷毀了,但其變量對象一直存在于內存中,就是為了能夠使得調用bar()函數時,可以通過作用域鏈訪問到父函數foo(),并得到其變量對象中儲存的變量值。直到頁面關閉,foo()函數的變量對象才會和全局的變量對象一起被銷毀,從而釋放內存空間

  由于閉包占用內存空間,所以要謹慎使用閉包。盡量在使用完閉包后,及時解除引用,以便更早釋放內存

//通過將baz置為null,解除引用
function foo(){var a = 2;function bar(){console.log(a);//2
    }return bar;
}
var baz = foo();
baz();        
baz = null;
/*后續代碼*/

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/260920.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/260920.shtml
英文地址,請注明出處:http://en.pswp.cn/news/260920.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

沒事寫著玩 系列之 JQ連連看(很丑陋,很初級)

說明:(圖片自備, 名稱為 jpg[0,2].jpg class為( one two three)對應 前面的 0,1,2) <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns"http://ww…

VS2017 調用Tesseract

最近在學tesseract&#xff0c;但遇到太多的問題是。 雖然網上有不少的方法&#xff0c;就算是按照tersseract&#xff0c;github上提供的方法也是編譯不成功。 問題一大堆。不過我也想到了其它方法最張還是可以用了。 我有2個方法&#xff0c; 方法1, 1&#xff0c;先build t…

最少步數----深搜

最少步數 時間限制&#xff1a;3000 ms | 內存限制&#xff1a;65535 KB難度&#xff1a;4描述這有一個迷宮&#xff0c;有0~8行和0~8列&#xff1a; 1,1,1,1,1,1,1,1,1 1,0,0,1,0,0,1,0,1 1,0,0,1,1,0,0,0,1 1,0,1,0,1,1,0,1,1 1,0,0,0,0,1,0,0,1 1,1,0,1,0,1,0,0,1 1,1,0,1…

由單例模式造成的內存泄漏

使用單例模式時&#xff0c;有時候不小心&#xff0c;就會很容易造成內容泄漏&#xff0c;如下代碼所示&#xff1a;public class SingleInstance { private static volatile SingleInstance instance; private Context context; private SingleInstance(Context context) {thi…

在windows上安裝OpenCV

在windows上安裝OpenCV&#xff0c;官方提供的教程&#xff0c;我翻譯了一下。如有不正解&#xff0c;請指正 使用git-bash&#xff08;版本> 2.14.1&#xff09;和cmake&#xff08;版本> 3.9.1&#xff09;安裝 1.您必須下載cmake&#xff08;版本> 3.9.1&…

CFile、CStdioFile、FILE和其他文件操作(轉)

CFile //創建/打開文件 CFile file; file.Open(_T("test.txt"),CFile::modeCreate|CFile::modeNoTruncate|CFile::modeReadWrite);//文件打開模式可組合使用&#xff0c;用“|”隔開&#xff0c;常用的有以下幾種&#xff1a; //CFile::modeCreate&#xff1a;以新建…

Oracle修改redo log大小的方法

目的:修改當前在線日志從默認50M增加至512M。1.查看當前日志組的狀態SQL> select group#,members,bytes/1024/1024,status from v$log;GROUP# MEMBERS BYTES/1024/1024 STATUS---------- ---------- --------------- ----------------1 1 50 INACT…

算法競賽入門經典 第一章 上機練習(C++代碼)

//平均數&#xff08;average&#xff09; //輸入3個整數&#xff0c;輸出它們的平均值&#xff0c;保留3位小數。 #include<iostream> #include<iomanip> using namespace std; int main() { int a,b,c; cin>>a>>b>>c; double average(abc)/3; …

CMake 編譯 OpenCV 項目,不是編譯OpenCV, 用了之后才知道CMake也太好用了。

新建一個 CMakeList.txt 復制下面代碼&#xff0c;并保存 cmake_minimum_required (VERSION 3.0)PROJECT(Chapter2)set (CMAKE_CXX_STANDARD 11)IF(EXISTS ${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)conan_basic_setup() E…

Java Ajax jsonp 跨域請求

2019獨角獸企業重金招聘Python工程師標準>>> 1. 什么是JSONP 一般來說位于 server1.example.com 的網頁無法與不是 server1.example.com的服務器溝通&#xff0c;而 HTML 的<script> 元素是一個例外。利用 <script> 元素的這個開放策略&#xff0c;網頁…

對IEnumerableT,IDictionaryTkey,TValue,ICollectionT,IListT的總結

1、IEnumerable<T>接口和IEnumerable接口 實現了IEnumerable接口的集合表明該集合能夠提供一個enumerator(枚舉器)對象&#xff0c;支持當前的遍歷集合。IEnumerable接口只有一個成員GetEnumerator()方法。 IEnumerator接口實現了IEnumerator接口的集合實現了從一個元素到…

Backup--修改實例級別是否使用壓縮備份的默認值

-- --修改實例級別是否使用壓縮備份的默認值 USE master; GO EXEC sp_configure backup compression default, 1; RECONFIGURE WITH OVERRIDE;轉載于:https://www.cnblogs.com/TeyGao/p/3519952.html

Java學習——Java運算符

位運算符 A 0011 1100 B 0000 1101 ----------------- A&b 0000 1100 A | B 0011 1101 A ^ B 0011 0001A << 2 1111 0000A >>> 2 0000 1111 ~A 1100 0011 例子 package import_test;public class Employee {public static void main(String args[])…

學習Python中用numpy與matplotlib遇到的一些數學函數與函數的繪圖

學習Python中的一些數學函數與函數的繪圖 主要用到numpy 與 matplotlib 如果有什么不正確&#xff0c;歡迎指教。 圖片不知道怎樣批量上傳&#xff0c;一個一個怎么感覺很小&#xff0c;請見諒 自行復制拷貝&#xff0c;到vs&#xff0c;jupyter notebook, spyder都可以 函…

控制臺輸出

getchar() system("pause") getch()//<conio.h>轉載于:https://www.cnblogs.com/lzihua/archive/2012/03/29/2422988.html

Linux基礎之文件權限詳解

Linux中對于權限的制定雖然沒有Windows的那么精細&#xff0c;但是如果你了解并掌握Linux中文件的權限知識&#xff0c;也可以像Windows那樣對權限做到精確配置。Linux中的文件權限是什么&#xff1f;如何查看Linux中的文件權限[rootlocalhost test]# ll -d /test/drwxr-xr-x. …

有這個OCR程序,不用再買VIP了,Python 調用百度OCR API

最近學習&#xff0c;很多東西都是視頻&#xff0c;截圖后&#xff0c;又想做成文檔保存起來。 剛開始不多&#xff0c;打一下字就很快解決了。 隨著時間的推移&#xff0c;現在越來越多的圖了&#xff0c;管理起來確實不方便&#xff0c;打字有時也不能很快的解決。 所以就…

android apk如何入門

android自己摸索了6,7個月不知道算不算入門&#xff01;對了只是應用層apk! 說說我的情況&#xff01;有C語言基礎&#xff0c;沒有接觸過JAVA語言。 1.先找視頻教程看&#xff0c;mars老師的&#xff01;不要理會java語言&#xff01;4季一氣看完&#xff01; 看了這個視頻教程…

linux常用命令_Linux常用命令全稱

從事IT行業的很多人都會使用Linux常用命令&#xff0c;但是知道這些常用命令全稱的人并不多&#xff0c;讓我們來看看這些常用命令對應的全稱吧&#xff01;必備Linux命令和C語言基礎_C語言_嵌入式開發工程師-創客學院?www.makeru.com.cnpwd:print work directory 打印當前目錄…

存儲程序(1)——MYSQL

MySQL支持把幾種對象存放在服務器端供以后使用。這幾種對象有一些可以根據情況通過程序代碼調用&#xff0c;有一些會在數據表被修改時自動執行&#xff0c;還有一些可以在預定時刻自動執行。它們包括以下幾種: 1.存儲函數(stored function)。返回一個計算結果&#xff0c;該結…