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 相关文章推荐
线路分流自动跳转代码;希望对大家有用!
Dec 02 Javascript
JavaScript动态调整TextArea高度的代码
Dec 28 Javascript
Javascript Request获取请求参数如何实现
Nov 28 Javascript
js用Date对象处理时间实现思路及代码
Jan 31 Javascript
JS实现标签页效果(配合css)
Apr 03 Javascript
用javascript添加控件自定义属性解析
Nov 25 Javascript
简介JavaScript中的setDate()方法的使用
Jun 11 Javascript
Node.js的MongoDB驱动Mongoose基本使用教程
Mar 01 Javascript
在原生不支持的旧环境中添加兼容的Object.keys实现方法
Sep 11 Javascript
JavaScript中set与get方法用法示例
Aug 15 Javascript
vue基础之事件简写、事件对象、冒泡、默认行为、键盘事件实例分析
Mar 11 Javascript
js回溯法计算最佳旅行线路代码实例
Sep 11 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
Oracle 常见问题解答
2006/10/09 PHP
Memcache 在PHP中的使用技巧
2010/02/08 PHP
基于php验证码函数的使用示例
2013/05/03 PHP
PHP扩展Memcache分布式部署方案
2015/12/06 PHP
PHP调用接口用post方法传送json数据的实例
2018/05/31 PHP
Alliance vs Liquid BO3 第一场2.13
2021/03/10 DOTA
js中将字符串转换成json的三种方式
2011/01/12 Javascript
JS+CSS 制作的超级简单的下拉菜单附图
2013/11/22 Javascript
基于jQuery实现点击列表加载更多效果
2016/05/31 Javascript
jQuery日期范围选择器附源码下载
2017/05/23 jQuery
javaScript动态添加Li元素的实例
2018/02/24 Javascript
vue-router3.0版本中 router.push 不能刷新页面的问题
2018/05/10 Javascript
微信小程序picker组件关于objectArray数据类型的绑定方法
2019/03/13 Javascript
浅谈layer弹出层按钮颜色修改方法
2019/09/11 Javascript
详解用js代码触发dom事件的实现方案
2020/06/10 Javascript
vue组件开发之slider组件使用详解
2020/08/21 Javascript
vue-cli4使用全局less文件中的变量配置操作
2020/10/21 Javascript
详解Python中的各种函数的使用
2015/05/24 Python
Python抓取聚划算商品分析页面获取商品信息并以XML格式保存到本地
2018/02/23 Python
pygame游戏之旅 游戏中添加显示文字
2018/11/20 Python
Python 使用指定的网卡发送HTTP请求的实例
2019/08/21 Python
pytorch多GPU并行运算的实现
2019/09/27 Python
5款实用的python 工具推荐
2020/10/13 Python
python实现经纬度采样的示例代码
2020/12/10 Python
html5清空画布方法(三种)
2017/10/16 HTML / CSS
Holiday Inn中国官网:IHG旗下假日酒店预订
2018/04/08 全球购物
Pottery Barn阿联酋:购买家具、家居装饰及更多
2019/12/08 全球购物
远东集团网络工程师面试题
2014/10/20 面试题
Servlet如何得到客户端机器的信息
2014/10/17 面试题
最新自我评价范文
2013/11/16 职场文书
安全教育感言
2014/03/04 职场文书
大学生英语演讲稿
2014/04/24 职场文书
2014法制宣传日活动总结范文
2014/11/01 职场文书
房屋分割离婚协议书范本
2014/12/01 职场文书
nginx location优先级的深入讲解
2021/03/31 Servers
一文解答什么是MySQL的回表
2022/08/05 MySQL