JavaScript作用域链实例详解


Posted in Javascript onJanuary 21, 2019

本文实例讲述了JavaScript作用域链。分享给大家供大家参考,具体如下:

跟其他语言一样,变量和函数的作用域揭示了这些变量和函数的搜索路径。对于JavaScript而言,理解作用域更加重要,因为在JavaScript中,作用域可以用来确定this的值,并且JavaScript有闭包,闭包是可以访问外部环境的作用域的。
每一个JavaScript的函数都是Function对象的一个实例,Function对象有一个内部属性[[Scope]],这个属性只能被JavaScript的引擎访问。通过[[Scope]]属性可以访问函数的作用域链,从而可以搜索变量和函数,判断变量和函数位于作用域链中的哪一个活动对象中。

简单的作用域链

当一个函数被创建的时候,因为函数是Function对象的一个实例,因此也会有[[Scope]]这个内部属性,Scope属性指向一个作用域链,作用域链中默认至少包含一个全局对象变量。

function compare(value1, value2){
  if (value1 < value2) {
    return -1;
  } else if (value1 > value2) {
    return 1;
  } else {
    return 0;
  }
}
var result = compare(5, 10);

以上代码先定义了一个compare()函数,然后在全局作用域中调用了这个函数。 在创建compare()函数的时候,该函数的作用域链如下图所示:

JavaScript作用域链实例详解

compare()函数在全局作用域中被调用执行的时候,JavaScript引擎会创建一个运行时上下文(execution context)的内部对象,一个运行时上下文定义了一个函数执行时的环境。函数诶次执行时的运行时上下文都是不同的,因此多次调用就会导致多个运行时上下文的创建与销毁。

每个运行时上下文都有自己的作用域链,用于变量和函数这些标识符的解析。

运行时上下文在函数调用执行时被创建,在函数执行完毕的时候被销毁。在运行时上下文创建的时候,首先会复制该被调用函数的[[Scope]]属性中的对象,然后一个活动对象(作为变量对象使用)会被创建并推入运行时上下文作用域链的前端。对于这个例子中compare()函数的运行时上下文而言,其作用域链包含两个变量对象:compare()的活动对象(activation object of compare())与全局变量对象(global object)。

对于简单的作用域链,就是这样了,但是有闭包的情况会有所不同。

JavaScript作用域链实例详解

闭包的作用域链

//step1: define createComparisonFunction
function createComparisonFunction(propertyName){
  return function(object1, object2){
    var value1 = object1[propertyName];
    var value2 = object2[propertyName];
    if (value1 < value2) {
      return -1;
    } else if (value1 > value2) {
      return 1;
    } else {
      return 0;
    }
  };
}
//step2: call createComparisonFunction
var compare = createComparisonFunction("name");
//step3: call compare
var result = compare({name: "Nicholas"}, {name: "Gerg"});
//step4: dereference closure for recycle memory
compare = null;

我们分下列几个步骤来图解作用域链:

step1: 定义createComparisonFunction;

JavaScript作用域链实例详解

在创建createComparisonFunction函数之后,createComparisonFunction可以被调用了,因此一个createComparisonFunction的Function对象被保留下来;
此时内存中保留对象:

1. Global Object

2. createComparisonFunction对象 & Scope Chain

step2: 执行createComparisonFunction;

JavaScript作用域链实例详解

在执行createComparisonFunction的过程中,首先会创建createComparisonFunction的运行时上下文对象 + ScopeChain + 活动对象,其次会创建一个闭包(匿名函数),
函数执行时内存中保留对象:

1. Global Object
2. createComparisonFunction的Function对象 + Scope Chain
3. createComparisonFunction的运行时上下文对象 + Scope Chain
4. createComparisonFunction的活动对象
5. Closure(anonymous)的Function对象 + Scope Chain

在执行完createComparisonFunction之后,createComparisonFunction的运行时上下文对象+ScopeChain会被销毁,但是createComparisonFunction的活动对象因为被Closure(anonymous)对象的ScopeChain所引用,因此不会被销毁。

函数执行完内存中保留对象:

1. Global Object
2. createComparisonFunction的Function对象 + Scope Chain
3. Closure(anonymous)的Function对象 + Scope Chain
4. createComparisonFunction的活动对象

对比step1, step2在执行完之后,增加了两个对象:

1. Closure(anonymous)的Function对象 + Scope Chain
2. createComparisonFunction的活动对象

这个是因为执行createComparisonFunction所产生的闭包被compare所引用了,而这个闭包函数的Scope Chain又引用了createComparisonFunction的活动对象,因此内存增加了这两个对象。

step3: 执行compare;

JavaScript作用域链实例详解

在执行在执行闭包(compare)的时候,首先会创建闭包的运行时上下文对象 + ScopeChain + 活动对象,然后执行闭包。

闭包执行时内存中保留对象:

1. Global Object
2. createComparisonFunction的Function对象 + Scope Chain
3. 闭包Closure(anonymous)的Function对象 + Scope Chain
4. createComparisonFunction的活动对象
5. 闭包Closure(anonymous)的运行时上下文 + Scope Chain
6. 闭包Closure(anonymous)的活动对象

执行完闭包Closure(anonymous)之后,闭包Closure(anonymous)的活动对象会被销毁,闭包Closure(anonymous)的运行时上下文 + Scope Chain也会被销毁。

闭包执行完内存中保留对象:

1. Global Object
2. createComparisonFunction的Function对象 + Scope Chain
3. 闭包Closure(anonymous)的Function对象 + Scope Chain
4. createComparisonFunction的活动对象

对比step2,step3执行完毕之后,内存中保留的对象没有增加,这就是正常执行一个函数的情况。

在正常情况下,执行完一个函数之后,内存中保留的对象应该与执行前一样的。

执行闭包因为没有引入新的引用,所以内存中保留的对象保持了一致。

那么问题来了,createComparisonFunction的活动对象到底怎么才能被销毁呢?

我们首先看createComparisonFunction的活动对象存在的原因是闭包Closure(anonymous)的Function对象的Scope Chain引用了createComparisonFunction的活动对象,其目的是因为闭包中需要访问propertyName这个createComparisonFunction的活动对象中的属性。

如果闭包Closure(anonymous)的Function对象被销毁之后,createComparisonFunction的活动对象因为没有被任何对象引用,也会被销毁。

step4解除了compare对闭包的引用,就使得闭包没有被任何对象引用,闭包销毁,从而使得createComparisonFunction的活动对象因为没有被任何对象引用,也会被销毁,这样就回收了这些对象所占用的内存。

使用闭包的问题就是内存消耗会比一般的函数大,因为要保存额外的活动对象,所以在不需要使用闭包的时候,需要将闭包解引用,回收额外的活动对象所占用的内存。

执行完step4之后内存中保留的对象:

1. Global Object

2. createComparisonFunction的Function对象 + Scope Chain

对比step1,step4在执行完毕之后,没有额外的对象被保留在内存中,引用闭包所产生的额外对象都得到了回收。

希望本文所述对大家JavaScript程序设计有所帮助。

Javascript 相关文章推荐
jQuery chili图片远处放大插件
Nov 30 Javascript
jquery html动态生成select标签出问题的解决方法
Nov 20 Javascript
整理的比较全的event对像在ie与firefox浏览器中的区别
Nov 25 Javascript
在页面中输出当前客户端时间javascript实例代码
Mar 02 Javascript
JS表格组件BootstrapTable行内编辑解决方案x-editable
Sep 01 Javascript
详解webpack编译多页面vue项目的配置问题
Dec 11 Javascript
javaScript中&quot;==&quot;和&quot;===&quot;的区别详解
Mar 16 Javascript
vue+echarts实现动态绘制图表及异步加载数据的方法
Oct 17 Javascript
axios实现简单文件上传功能
Sep 25 Javascript
Vue移动端实现图片上传及超过1M压缩上传
Dec 23 Javascript
vue调用本地摄像头实现拍照功能
Aug 14 Javascript
在vue中嵌入外部网站的实现
Nov 13 Javascript
Jquery的Ajax技术使用方法
Jan 21 #jQuery
js变量声明var使用与不使用的区别详解
Jan 21 #Javascript
Vue中Axios从远程/后台读取数据
Jan 21 #Javascript
vue项目中实现的微信分享功能示例
Jan 21 #Javascript
在vue项目中引入highcharts图表的方法
Jan 21 #Javascript
js的对象与函数详解
Jan 21 #Javascript
JS实现求5的阶乘示例
Jan 21 #Javascript
You might like
php下一个阿拉伯数字转中文数字的函数
2007/07/16 PHP
基于PHP生成静态页的实现方法
2013/05/10 PHP
destoon安全设置中需要设置可写权限的目录及文件
2014/06/21 PHP
php表单加入Token防止重复提交的方法分析
2016/10/10 PHP
PHP开发之归档格式phar文件概念与用法详解【创建,使用,解包还原提取】
2017/11/17 PHP
php中输出json对象的值(实现方法)
2018/03/07 PHP
QQ登录简单实现代码
2021/03/09 Javascript
window.name代替cookie的实现代码
2010/11/28 Javascript
js判断字符长度及中英文数字等
2014/03/19 Javascript
jquery-syntax动态语法着色示例代码
2014/05/14 Javascript
Google 地图API Map()构造器详解
2016/08/06 Javascript
基于cssSlidy.js插件实现响应式手机图片轮播效果
2016/08/30 Javascript
在vue中,v-for的索引index在html中的使用方法
2018/03/06 Javascript
用Node提供静态文件服务的方法
2018/07/06 Javascript
JavaScript布尔运算符原理使用解析
2020/05/06 Javascript
详解JavaScript 作用域
2020/07/14 Javascript
python每次处理固定个数的字符的方法总结
2013/01/29 Python
python实现的简单FTP上传下载文件实例
2015/06/30 Python
在DigitalOcean的服务器上部署flaskblog应用
2015/12/19 Python
KMP算法精解及其Python版的代码示例
2016/06/01 Python
Python中的取模运算方法
2018/11/10 Python
详解Python循环作用域与闭包
2019/03/21 Python
TensorFLow 数学运算的示例代码
2020/04/21 Python
HTML5 video进入全屏和退出全屏的实现方法
2020/07/28 HTML / CSS
Alba Moda德国网上商店:意大利时尚女装销售
2016/11/14 全球购物
英国知名小木屋定制网站:Tiger Sheds
2020/03/06 全球购物
init进程的作用
2012/04/12 面试题
骨干教师培训制度
2014/01/13 职场文书
工会换届选举方案
2014/05/21 职场文书
合作协议书模板2014
2014/09/26 职场文书
2014党的群众路线教育实践活动总结报告
2014/10/31 职场文书
检讨书范文
2015/01/27 职场文书
男方家长婚礼致辞
2015/07/27 职场文书
大学同学聚会感言
2015/07/30 职场文书
一篇带你入门Java垃圾回收器
2021/06/16 Java/Android
电脑关机速度很慢怎么办 提升电脑关机速度设置教程
2022/04/08 数码科技