`

JavaScript 作用域链解析

 
阅读更多

 

最近看了下JavaScript方面的几本书,把里面的一些核心概念按照自己的理解做个总结。

 

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( 全局上下文 ) 。如果用图形形象化的表述如下图所示:


 

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

 

动态方面:

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

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



 从上图可以看出,执行上下文是一个动态的概念,它是当函数运行的时候创建的,同时 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 最神秘的 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 函数运行期的情形:



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

 

 



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

 

参考资料:

1.High Performance JavaScript. http://book.douban.com/subject/5362856/

2.JavaScript高级程序设计. http://book.douban.com/subject/4886879/

 

 

 

 

 

  • 大小: 21 KB
  • 大小: 35.2 KB
  • 大小: 50.4 KB
  • 大小: 43.4 KB
  • 大小: 43.4 KB
1
0
分享到:
评论
3 楼 ynyee 2012-05-27  
那闭包的生成以后怎么销毁?
2 楼 狂放不羁 2011-12-15  
oojdon 写道
我现在的理解是代码被执行,就形成了闭包,代码没执行那就还是代码

你的理解是对的。哥们。
1 楼 oojdon 2011-12-15  
我现在的理解是代码被执行,就形成了闭包,代码没执行那就还是代码

相关推荐

    Javascript作用域和作用域链原理解析

    作用域和作用域链在Javascript和很多其它的编程语言中都是一种基础概念。但很多Javascript开发者并不真正理解它们,但这些概念对掌握Javascript至关重要。 正确的去理解这个概念有利于你去写更好,更高效和更简洁的...

    JavaScript作用域与作用域链深入解析

    作用域是JavaScript最重要的概念之一,想要学好JavaScript就需要理解JavaScript作用域和作用域链的工作原理。今天这篇文章对JavaScript作用域和作用域链作简单的介绍,希望能帮助大家更好的学习JavaScript。 ...

    javascript作用域链(Scope Chain)用法实例解析

    主要介绍了javascript作用域链(Scope Chain)用法,结合实例形式较为详细的分析了javascript作用域链(Scope Chain)的概念、功能与相关使用技巧,具有一定参考借鉴价值,需要的朋友可以参考下

    JavaScript — 原型链与作用域链1

    i++) {// 块级作用域}作用域每次执行都会生成一个新的活动对象作用域内的所有变量自动成为活动对象中的属性只有在作用域执行时才解析活动对象内的属性值作用域每

    javascript作用域链与执行环境详解

    作用域、作用域链、执行环境、执行环境栈以及this的概念在javascript中非常重要,本人经常弄混淆,这里梳理一下; 局部作用域函数内部的区域,全局作用域就是window; 作用域链取决于函数被声明时的位置,解析...

    js作用域和作用域链及预解析

    作用域链:变量的使用,从里向外,层层的搜索,搜索到了就可以直接使用了 层层搜索,搜索到0级作用域的时候,如果还是没有找到这个变量,结果就是报错 在 JavaScript 中, 对象和函数同样也是变量。 在 JavaScript 中, 作用...

    浅析JavaScript中作用域和作用域链

    本文主要介绍了JavaScript中作用域和作用域链解析,条理分明,方便理解,这里推荐给小伙伴们,有需要的朋友可以参考下

    javascript中作用域以及作用域链

    变量及作用域: 变量无非就是两种:全局变量和局部...(也就是说预解析的时候就已经确定了作用域,在函数没有运行的时候就已经确定了) // 词法作用域(静态作用域) let abc = 123 function fn1 () { console.log(abc)

    深入解析JavaScript中的变量作用域

    •JavaScript的变量作用域是基于其特有的作用域链的。 •JavaScript没有块级作用域。 •函数中声明的变量在整个函数中都有定义。 1、JavaScript的作用域链首先看下下面这段代码: 代码如下:[removed] var rain = 1; ...

    深入理解JavaScript系列(14) 作用域链介绍(Scope Chain)

    这一章专门讨论与执行上下文直接相关的更多细节,这次我们将提及一个议题——作用域链。 英文原文:http://dmitrysoshnikov.com/ecmascript/chapter-4-scope-chain/ 中文参考:http://www.denisdeng.com/?p=908 ...

    关于javascript作用域的常见面试题分享

    本文主要给大家分享了关于javascript作用域面试题的相关内容,分享出来供大家参考学习,下面来一起看看吧。 一、作用域: 在了解作用域之前,首先需要明白一些基础概念: 每一个变量、函数都有其作用的范围,超出...

    预解析&作用域1

    预解析&作用域1

    JavaScript变量的作用域全解析

    主要介绍了JavaScript变量的作用域的基本知识,是JavaScript入门学习中的基础知识,需要的朋友可以参考下

    第六章:js解析顺序和作用域1

    第13节:js解析顺序和作用域javascript解析顺序(定义)先解析var、function、参数;该步骤的var只定义变量,后面的 = 赋值不解析该步骤的

Global site tag (gtag.js) - Google Analytics