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 相关文章推荐
JS获取父节点方法
Aug 20 Javascript
对JavaScript的全文搜索实现相关度评分的功能的方法
Jun 24 Javascript
JS+CSS实现的简单折叠展开多级菜单效果
Sep 12 Javascript
详解JavaScript 中的 replace 方法
Jan 01 Javascript
原生javascript实现的一个简单动画效果
Mar 30 Javascript
JavaScript实现邮箱地址自动匹配功能代码
Nov 28 Javascript
JS中Safari浏览器中的Date
Jul 17 Javascript
vue 优化CDN加速的方法示例
Sep 19 Javascript
利用JavaScript缓存远程窃取Wi-Fi密码的思路详解
Nov 05 Javascript
深入理解Vue keep-alive及实践总结
Aug 21 Javascript
layui输入框中只允许输入整数的实现方法
Sep 18 Javascript
Vue 中使用lodash对事件进行防抖和节流操作
Jul 26 Javascript
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
php fsockopen伪造post与get方法的详解
2013/06/14 PHP
php微信开发自定义菜单
2016/08/27 PHP
js判断IE6/IE7/FF的代码[XMLHttpRequest]
2011/02/16 Javascript
js中Image对象以及对其预加载处理示例
2013/11/20 Javascript
浅谈checkbox的一些操作(实战经验)
2013/11/20 Javascript
JavaScript中数组成员的添加、删除介绍
2014/12/30 Javascript
jQuery原型属性和原型方法详解
2015/07/07 Javascript
JS实现模拟百度搜索“2012世界末日”网页地震撕裂效果代码
2015/10/31 Javascript
深入浅析javascript中的作用域(推荐)
2016/07/19 Javascript
两行代码轻松搞定JavaScript日期验证
2016/08/03 Javascript
jQuery对table表格进行增删改查
2020/12/22 Javascript
el表达式 写入bootstrap表格数据页面的实例代码
2017/01/11 Javascript
纯JS实现弹性导航条效果
2017/03/06 Javascript
基于vuejs实现一个todolist项目
2017/04/11 Javascript
vue.js项目 el-input 组件 监听回车键实现搜索功能示例
2018/08/25 Javascript
React Native开发封装Toast与加载Loading组件示例
2018/09/08 Javascript
微信小程序调用天气接口并且渲染在页面过程详解
2019/06/24 Javascript
layui文件上传控件带更改后数据传值的方法
2019/09/23 Javascript
javascript设计模式 ? 建造者模式原理与应用实例分析
2020/04/10 Javascript
Vue 同步异步存值取值实现案例
2020/08/05 Javascript
pymongo给mongodb创建索引的简单实现方法
2015/05/06 Python
Tornado 多进程实现分析详解
2018/01/12 Python
Python实现的视频播放器功能完整示例
2018/02/01 Python
解决os.path.isdir() 判断文件夹却返回false的问题
2019/11/29 Python
基于Tensorflow的MNIST手写数字识别分类
2020/06/17 Python
pycharm最新激活码有效期至2100年(亲测可用)
2021/02/05 Python
CSS3基础(RGBa、text-shadow、box-shadow、border-radius)
2012/11/13 HTML / CSS
使用简单的CSS3属性实现炫酷读者墙效果
2014/01/08 HTML / CSS
css3新单位vw、vh的使用教程
2018/03/23 HTML / CSS
JACK & JONES荷兰官网:男士服装和鞋子
2021/03/07 全球购物
岗位职责怎么写
2014/03/14 职场文书
农业项目建议书
2014/08/25 职场文书
基层领导干部“四风”问题批评与自我批评
2014/09/23 职场文书
师德标兵先进事迹材料
2014/12/19 职场文书
python opencv通过4坐标剪裁图片
2021/06/05 Python
Android自定义scrollview实现回弹效果
2022/04/01 Java/Android