深入理解闭包系列第二篇——从执行环境角度看闭包
前面的话
本文从执行环境的角度来分析闭包,先用一张图开宗明义,然后根据图示内容对代码进行逐行说明,试图对闭包进行更直观的解释
图示
说明
下面按照代码执行流的顺序对该图示进行详细说明
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; /*后续代码*/
深入理解闭包系列第二篇——从执行环境角度看闭包相关推荐
- 深入理解定时器系列第二篇——被誉为神器的requestAnimationFrame
前面的话 与setTimeout和setInterval不同,requestAnimationFrame不需要设置时间间隔.这有什么好处呢?为什么requestAnimationFrame被称为神器呢 ...
- 深入理解javascript函数系列第二篇——函数参数
前面的话 javascript函数的参数与大多数其他语言的函数的参数有所不同.函数不介意传递进来多少个参数,也不在乎传进来的参数是什么数据类型,甚至可以不传参数.本文是深入理解javascript函数 ...
- 前端工程师技能之photoshop巧用系列第二篇——测量篇
前端工程师使用photoshop进行的大量工作实际上是测量.本文是photoshop巧用系列第二篇--测量篇 测量信息 在网页制作中需要使用photoshop测量的信息分为两类,分别是尺寸信息和颜色信 ...
- 焱老师带你学习MYSQL系列 第二篇 (MYSQL 数据结构)
相关系列链接 焱老师带你学习MYSQL系列 第六篇 (MYSQL是如何实现锁的) 焱老师带你学习MYSQL系列 第五篇 (MYSQL事务隔离级别是如何实现的) 焱老师带你学习MYSQL系列 第四篇 ( ...
- [游戏开发]Python打表工具系列 [第二篇] [打表流程描简述]
[上一篇链接] [游戏开发]Python打表工具系列 [第一篇][IDE开发环境部署] VSCode Python环境调试_Little丶Seven的博客-CSDN博客 [前言] 第二篇文章是对流程的 ...
- js执行环境作用域和闭包_JavaScript中执行上下文,提升,作用域和闭包的终极指南
js执行环境作用域和闭包 It may seem surprising, but in my opinion the most important and fundamental concept to ...
- 阿里出品移动研发“神器” 阿里移动云系列第二篇|“移”步到位:一站式移动应用研发体系...
摘要:2017杭州云栖大会阿里移动云峰会专场上,阿里巴巴高级技术专家小木带来一站式应用研发体系方面的演讲.本文主要以互联网的应用背景开始谈起,进而阐述了已拥有APP的企业在APP的生命周期中会遇见哪些 ...
- SparkContext的初始化(伯篇)——执行环境与元数据清理器
<深入理解Spark:核心思想与源码分析>一书前言的内容请看链接<深入理解SPARK:核心思想与源码分析>一书正式出版上市 <深入理解Spark:核心思想与源码分析> ...
- 带有执行环境的函数 - 闭包
学习 JavaScript 的同学都会面对闭包,总觉得很难,你会看到闭包各种版本的定义,即使把闭包的概念背会也不一定的能够理解闭包.想要掌握闭包,需要看很多关于闭包的资料,加上对 JavaScript ...
最新文章
- react非常适合入门者学习使用的后台管理框架
- awk截取字符命令_Linux运维基础技能: 脚本编程与Linux命令
- 移动互联网的创新与91生态
- 产品定义到产品推广的思路
- 对话中国经济和信息化-万祥军:李玉庭制造企业重整电商
- CENTOS7 Python3.7安装pip模块以及pip使用
- 一个IT人士的个人经历,给迷失方向的朋友
- pta l2-6(树的遍历)
- 洛谷 P5742、P5743、P5744 题解
- ftp加速传输java_Java FTPClient 大量数据传输的问题(未解决)
- Websphere 手动模拟删除应用操作
- 年底绝对不能犯的四个职场错误
- 基于Monorail的系统功能模块化
- u盘无法格式化不在计算机中,u盘被写保护无法格式化怎么办 u盘无法格式化原因及解决...
- 计算机管理内存条,win10系统查看电脑内存条型号的方法
- 腾讯企业邮箱好还是阿里云企业邮箱好?
- 转换、刻录DVD影碟光盘教程
- 每周分享第 31 期
- IE8跳转谷歌浏览器亲测有效
- 大数据未来发展趋势,主要取决于这八个要素