JavaScript 作用域链解析


Posted in Javascript onNovember 13, 2014

JavaScript中有Scope(作用域),Scope chain(作用域链),Execute context(执行上下文),Active Object (活动对象),Dynamic Scope(动态作用域),Closure(闭包)这些概念,要理解这些概念,我们从静态和动态两个方面去分析一下。

首先我们写一个简单的function来做一个例子:

function add(num1, num2){

var sum = num1 + num2;

return sum;

}

我们定义了一个具有两个形参的add函数。

静态方面:

当创建add函数的时候,Javascript引擎会创建add函数的Scope chain,这个作用域链指向了Global Context(全局上下文)。如果用图形形象化的表述如下图所示:

JavaScript 作用域链解析

从上图可以看出,当add函数创建的时候,作用域链就已经创建了,因此可以得出一个结论,函数的作用域链是创建函数的时候就已经创建了,而不是动态运行期。下面就来看看动态运行期的时候会发生什么事情。

动态方面:

当执行add函数的时候,JavaScript会创建一个Execute context(执行上下文),执行上下文中就包含了add函数运行期所需要的所有信息。Execute context也有自己的Scope chain,当函数运行的时候,JavaScript引擎会首先从用add函数的作用域链来初始化执行上下文的作用域链,然后JavaScript引擎又会创建一个Active Object,这个对象里面包含了函数运行期的所有局部变量,参数以及this等变量。

如果形象的描述add函数动态运行期会发生什么,可以用如下图来描述:

JavaScript 作用域链解析

从上图可以看出,执行上下文是一个动态的概念,它是当函数运行的时候创建的,同时Active Object对象也是一个动态的概念,它是被执行上下文的作用域链引用的。因此可以得出一个结论:执行上下文和活动对象都是动态概念,并且执行上下文的作用域链是由函数作用域链初始化的。

上面说了函数作用域和执行上下文作用域,下面接着说一下动态作用域的问题,当在JavaScript通过with语句,try-catch的catch子句,以及eval方法的时候,JavaScript引擎就会动态的改变执行上下文的作用域。下面还是通过一个例子来看看:

function initUI(){  

  with (document){ //avoid!  

  var bd = body,  

  links = getElementsByTagName("a"),  

  i= 0,  

  len = links.length;  

  while(i < len){  

  update(links[i++]);  

}  

  getElementById("go-btn").onclick = function(){  

  start();  

};  

  bd.className = "active";  

} 

当执行上面的initUI函数的时候,JavaScript会动态的创建一个with语句对应的作用域放到执行上下文作用域链的最前端,通过下图可以形象的描述上述过程,下图红色标注的区域就显示了with语句产生的作用域。

JavaScript 作用域链解析

最后,我们来看看JavaScript最神秘的Closure(闭包),闭包在JavaScript其实就是一个函数,闭包是在函数运行期被创建的,下面还是以一个实例来看看:

function assignEvents(){  

    var id = "xdi9592";  

    document.getElementById("save-btn").onclick = function(event){  

    saveDocument(id);  

   };  

} 

当上面的assignEvents函数被执行的时候,会创建一个闭包,而这个闭包会引用assignEvents作用域中的id变量,如果按照传统的编程语言的方式,id是存储在堆栈上的一个变量,当函数执行完了以后id就消失,那么怎么可能再次引用呢?显然这里JavaScript采用了另外的方式。下面就来看看JavaScript是如何来实现闭包的。当执行assignEvents函数的时候,JavaScript引擎会创建assignEvents函数执行上下文的作用域链,这个作用域链包含了assignEvents执行时的活动对象,而同时JavaScript引擎也会创建一个闭包,而闭包的作用域链也会引用assignEvent执行时候的活动对象,这样当assignEvents执行完的时候,虽然它本身执行上下文的作用域链不再引用活动对象了,但是闭包还是引用着assignEvents运行期对应的活动对象,这就解释了JavaScipt内部的闭包机制。可以用下图形象的表述上面assignEvents函数运行期的情形:

JavaScript 作用域链解析

从上面可以看出,当assignEvents函数执行完毕以后,document.getElementById("save-btn").onclick引用了闭包,这样当用户点击save-btn的时候,就会触发闭包的执行,那么下面就来看看闭包执行时的情形。前面也说了JavaScript中闭包其实就是函数,因此闭包执行和函数执行时的情形是一致的,通过下图来形象的描述上述onclick事件所关联的闭包。

JavaScript 作用域链解析

从上图可以看出JavaScript引擎首先创建了闭包的执行上下文,然后用闭包作用域链来初始化闭包的执行上下文作用域链,最后再将闭包执行时对应的活动对象放入到作用域的最前端,这也进一步验证了闭包就是函数的论断。

Javascript 相关文章推荐
IE6中使用position导致页面变形的解决方案(js代码)
Jan 09 Javascript
javascript检测对象中是否存在某个属性判断方法小结
May 19 Javascript
extjs表格文本启用选择复制功能具体实现
Oct 11 Javascript
easyui datagrid 键盘上下控制选中行示例
Mar 31 Javascript
jquery进行数组遍历如何跳出当前的each循环
Jun 05 Javascript
js实现图片漂浮效果的方法
Mar 02 Javascript
jQuery实现复选框批量选择与反选的方法
Jun 17 Javascript
详解JavaScript逻辑Not运算符
Dec 04 Javascript
微信小程序开发教程-手势解锁实例
Jan 06 Javascript
深入理解node.js http模块
Jan 24 Javascript
vue项目支付功能代码详解
Feb 18 Vue.js
html中两种获取标签内的值的方法
Jun 16 jQuery
jQuery $命名冲突解决方案汇总
Nov 13 #Javascript
js获取字符串最后一位方法汇总
Nov 13 #Javascript
实现js保留小数点后N位的代码
Nov 13 #Javascript
详谈jQuery中的this和$(this)
Nov 13 #Javascript
FF(火狐)浏览器无法执行window.close()解决方案
Nov 13 #Javascript
jquery checkbox 勾选的bug问题解决方案与分析
Nov 13 #Javascript
Javascript window对象详解
Nov 12 #Javascript
You might like
关于crontab的使用详解
2013/06/24 PHP
php读取mysql中文数据出现乱码的解决方法
2013/08/16 PHP
Symfony2在Nginx下的配置方法图文教程
2016/02/04 PHP
PHP实现补齐关闭的HTML标签
2016/03/22 PHP
Yii2搭建后台并实现rbac权限控制完整实例教程
2016/04/28 PHP
php连接oracle数据库的核心步骤
2016/05/26 PHP
ThinkPHP框架表单验证操作方法
2017/07/19 PHP
php pdo连接数据库操作示例
2019/11/18 PHP
JS解密入门之凭直觉解
2008/06/25 Javascript
巧用replace将文字表情替换为图片
2014/04/17 Javascript
jQuery Easyui实现左右布局
2016/01/26 Javascript
js实现图片缓慢放大缩小效果
2016/08/02 Javascript
javascript笔记之匿名函数和闭包
2017/02/06 Javascript
js获取元素下的第一级子元素的方法(推荐)
2017/03/05 Javascript
JS排序之冒泡排序详解
2017/04/08 Javascript
小程序分页实践之编写可复用分页组件
2019/07/18 Javascript
[00:18]天涯墨客三技能展示
2018/08/25 DOTA
Python机器学习之K-Means聚类实现详解
2018/02/22 Python
详解pandas如何去掉、过滤数据集中的某些值或者某些行?
2019/05/15 Python
pygame库实现俄罗斯方块小游戏
2019/10/29 Python
python线程信号量semaphore使用解析
2019/11/30 Python
Transpose 数组行列转置的限制方式
2020/02/11 Python
如何将Pycharm中调整字体大小的方式设置为&quot;ctrl+鼠标滚轮上下滑&quot;
2020/11/17 Python
MONNIER Frères英国官网:源自巴黎女士奢侈品配饰电商平台
2018/12/06 全球购物
ColourPop美国官网:卡拉泡泡,洛杉矶彩妆品牌
2019/04/28 全球购物
Michael Kors澳大利亚官网:世界知名的奢侈饰品和成衣设计师
2020/02/13 全球购物
什么是Rollback Segment
2013/04/22 面试题
数据库的约束含义
2012/09/09 面试题
介绍一下Ruby的特点
2013/01/20 面试题
给民警的表扬信
2014/01/08 职场文书
感恩小明星事迹材料
2014/05/23 职场文书
2014最新开业庆典策划方案(5篇)
2014/09/15 职场文书
违规违纪检讨书范文
2015/05/06 职场文书
政审证明材料
2015/06/19 职场文书
JavaScript数组reduce()方法的语法与实例解析
2021/07/07 Javascript
Python如何使用循环结构和分支结构
2022/04/13 Python