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时遇到的一些小问题
Dec 06 Javascript
js文件包含的几种方式介绍
Sep 28 Javascript
node.js中的querystring.parse方法使用说明
Dec 10 Javascript
js实现动态创建的元素绑定事件
Jul 19 Javascript
前端 Vue.js 和 MVVM 详细介绍
Dec 29 Javascript
如何理解jQuery中的ajaxSubmit方法
Mar 13 Javascript
详解Angular 4.x NgTemplateOutlet
May 24 Javascript
IE11下使用canvas.toDataURL报SecurityError错误的解决方法
Nov 19 Javascript
微信小程序有旋转动画效果的音乐组件实例代码
Aug 22 Javascript
详解Webpack-dev-server的proxy用法
Sep 08 Javascript
详解JS实现简单的时分秒倒计时代码
Apr 25 Javascript
JavaScript 防盗链的原理以及破解方法
Dec 29 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获取MSN好友列表类的实现代码
2013/06/23 PHP
Thinkphp实现MySQL读写分离操作示例
2014/06/25 PHP
php批量删除数据库下指定前缀的表以prefix_为例
2014/08/24 PHP
php PDO实现的事务回滚示例
2017/03/23 PHP
实例讲解php实现多线程
2019/01/27 PHP
php curl操作API接口类完整示例
2019/05/21 PHP
基于php解决json_encode中文UNICODE转码问题
2020/11/10 PHP
javascript 字符串连接的性能问题(多浏览器)
2008/11/18 Javascript
给Function做的OOP扩展
2009/05/07 Javascript
提升你网站水平的jQuery插件集合推荐
2011/04/19 Javascript
jQuery的观察者模式详解
2014/12/22 Javascript
jQuery自动完成插件completer附源码下载
2016/01/04 Javascript
jQuery validate插件实现ajax验证重复的2种方法
2016/01/22 Javascript
js实现不重复导入的方法
2016/03/02 Javascript
WordPress 单页面上一页下一页的实现方法【附代码】
2016/03/10 Javascript
Javascript中引用类型传递的知识点小结
2017/03/06 Javascript
webpack配置文件和常用配置项介绍
2017/04/28 Javascript
Angular中支持SCSS的方法
2017/11/18 Javascript
详解nodejs http请求相关总结
2019/03/31 NodeJs
微信小程序全局变量GLOBALDATA的定义和调用过程解析
2019/09/23 Javascript
在layer弹层layer.prompt中,修改placeholder的实现方法
2019/09/27 Javascript
利用JavaScript为句子加标题的3种方法示例
2021/01/05 Javascript
Python中的闭包详细介绍和实例
2014/11/21 Python
Python3.2中Print函数用法实例详解
2015/05/19 Python
python利用rsa库做公钥解密的方法教程
2017/12/10 Python
人工神经网络算法知识点总结
2019/06/11 Python
Pytorch 实现sobel算子的卷积操作详解
2020/01/10 Python
python中安装django模块的方法
2020/03/12 Python
在Matplotlib图中插入LaTex公式实例
2020/04/17 Python
python爬虫如何解决图片验证码
2021/02/14 Python
英国二手物品交易网站:Preloved
2017/10/06 全球购物
学校节能减排倡议书
2014/05/16 职场文书
2016教师学习党章心得体会
2016/01/15 职场文书
Python 实现定积分与二重定积分的操作
2021/05/26 Python
详解Java实现数据结构之并查集
2021/06/23 Java/Android
阿里云服务器(windows)手动部署FTP站点详细教程
2022/08/05 Servers