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 相关文章推荐
JavaScript多线程的实现方法
May 08 Javascript
AngularJS中如何使用$http对MongoLab数据表进行增删改查
Jan 23 Javascript
js实现页面跳转的五种方法推荐
Mar 10 Javascript
Three.js学习之文字形状及自定义形状
Aug 01 Javascript
Vue.js使用v-show和v-if的注意事项
Dec 13 Javascript
canvas绘图不清晰的解决方案
Feb 28 Javascript
详解使用vue-admin-template的优化历程
May 20 Javascript
了解javascript中let和var及const关键字的区别
May 24 Javascript
uni-app微信小程序登录并使用vuex存储登录状态的思路详解
Nov 04 Javascript
浅析我对JS延迟异步脚本的思考
Oct 12 Javascript
jQuery-App输入框实现实时搜索
Nov 19 jQuery
JavaScript async/await原理及实例解析
Dec 02 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学习之运算符相关概念
2011/06/09 PHP
php设计模式 Observer(观察者模式)
2011/06/26 PHP
基于PHP异步执行的常用方式详解
2013/06/03 PHP
Laravel 中获取上一篇和下一篇数据
2015/07/27 PHP
Yii2-GridView 中让关联字段带搜索和排序功能示例
2017/01/21 PHP
php设计模式之观察者模式定义与用法经典示例
2019/09/19 PHP
php设计模式之观察者模式实例详解【星际争霸游戏案例】
2020/03/30 PHP
获取任意Html元素与body之间的偏移距离 offsetTop、offsetLeft (For:IE5+ FF1 )[
2006/12/22 Javascript
基于jquery实现的可以编辑选择的下拉框的代码
2010/11/19 Javascript
jQuery实现高亮显示网页关键词的方法
2015/08/07 Javascript
JavaScript 函数的定义-调用、注意事项
2017/04/16 Javascript
微信小程序分页加载的实例代码
2017/07/11 Javascript
VSCode中如何利用d.ts文件进行js智能提示
2018/04/13 Javascript
vue组件实现可搜索下拉框扩展
2020/10/23 Javascript
使用node搭建自动发图文微博机器人的方法
2019/03/22 Javascript
layui prompt 设置允许空白提交的方法
2019/09/24 Javascript
Python HTMLParser模块解析html获取url实例
2015/04/08 Python
用Python遍历C盘dll文件的方法
2015/05/06 Python
win10环境下python3.5安装步骤图文教程
2017/02/03 Python
Python使用asyncio包处理并发详解
2017/09/09 Python
Python数据结构与算法之二叉树结构定义与遍历方法详解
2017/12/12 Python
Python 3.x基于Xml数据的Http请求方法
2018/12/28 Python
pygame实现俄罗斯方块游戏(对战篇1)
2019/10/29 Python
tensorflow 动态获取 BatchSzie 的大小实例
2020/06/30 Python
四种会话跟踪技术
2015/05/20 面试题
最经典的大学生职业生涯规划范文
2014/03/05 职场文书
专题组织生活会方案
2014/06/15 职场文书
高一军训的心得体会
2014/09/01 职场文书
大学生军训自我鉴定范文
2014/09/18 职场文书
二手房购房协议书范本
2014/10/05 职场文书
2014年团支部工作总结
2014/11/17 职场文书
副总经理岗位职责
2015/02/02 职场文书
护士长2015年终工作总结
2015/04/24 职场文书
孙振耀退休感言
2015/08/01 职场文书
汉语拼音教学反思
2016/02/22 职场文书
win11怎么用快捷键锁屏? windows11锁屏的几种方法
2021/11/21 数码科技