JavaScript的闭包与作用域链

闭包算是JavaScript最强大的特性之一了,它允许函数访问局部作用域之外的数据。在许多复杂web应用及很多JavaScript库里面(例如jQuery),我们都可以看到它的身影。

什么是闭包呢?

闭包是指程序中的代码块允许一级函数存在(function1)并且在一级函数中所定义的自由变量(x、y)能不被释放,直到一级函数被释放前,一级函数外也能应用这些未释放的自由变量(看不懂没关系,待会回头再看)。

要说明闭包底层的原理,我们就要弄明白一个“作用域链”的概念。

1、作用域链

当我们声明一个函数的时候,我们创建了一个Function对象的实例:

function add(num1, num2){
    var sum = num1 + num2;
    return sum;
}

这个Function实例中有一个内部属性,叫[[Scope]],仅供JavaScript引擎访问(就像Java中private的属性),[[Scope]]指向一个集合,即为“作用域链(Scope chain)”,这个集合决定了哪些数据能被函数访问。

当这个add()被创建的时候,它的作用域链中就被填入了一个全局对象(Global object),表示了全局范围定义的变量

 

当我们运行一个函数的时候,会产生一个“运行期上下文(execution context)”的内部对象,定义了一个函数执行时的环境,函数每次运行都会产生一个独一无二的“运行期上下文”,当函数执行完毕后,“运行期上下文”就被销毁

var total = add(5,10);

每个“运行期上下文”都有自己的“作用域链”,用于标识符的解释。当“运行期上下文”被创建的时候,它将复制该函数内部属性[[Scope]]的值,到自己的“作用域链”中。然后,将创建一个“活动对象(Activation object)”,其中包含了局部变量、参数集合、this等,此“活动对象”将被放入“作用域链”的前端。当“运行期上下文”被销毁,“活动对象”也随之销毁。

2、闭包

那闭包的时候又是怎么回事呢?让我们看回《jQuery源码学习(1)》里面的代码:

var test=function(y){    //function1
    var x=y;// 这个是局部变量
    return function(){  //function2
     alert(x++);// 就是这里调用了闭包特性中的
     //一级函数局部变量的x,并对它进行操作
     alert(y--);// 引用的参数变量也是自由变量
    }}(5);// 后面这个(5),让前面的函数运行了,abc被初始化为function2

test();// "5" "5" function1之外(function2),能够继续调用x、y
test();// "6" "4"
test();// "7" "3"

当匿名函数function1被执行的时候,将创建一个“闭包(Closure)”,也就是function2。为了让这个“闭包”能够访问function1的变量,必须创建一个特定的作用域链:

因为“闭包”的[[Scope]]属性包含了与“运行期上下文”相同的对象引用,当一级函数运行完毕之后,它的“活动对象”的引用依旧存在于“闭包”的[[Scope]]属性中,所以一级函数的“活动对象”无法被销毁(即一级函数运行完毕后,闭包函数依旧能够范围一级函数内的变量)。

当“闭包”函数被执行时,一个“运行期上下文”被创建,其作用域链将如下图所示:

闭包的原理就先说到这里。

3、undefined的真正原因

说回网易那次笔试的题目:

var a=100;
(function(){
    alert(a);
    var a=1;
})()

为什么输出的是undefined呢,因为遍历“作用域链”寻找变量的时候,先遇到了“活动对象”中的a,此时它尚未被赋值,故为undefined。

 

参考资料:《高性能JavaScript

我说:那本书是淘宝UED的博客上推荐的~

发布者

Rolf

伪文艺IT攻城师,热爱前端,热爱互联。

《JavaScript的闭包与作用域链》有3个想法

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

[喜欢] [嘻嘻] [奋斗] [问号] [鼓掌] [泪] [酷] [强] [耶] [握手] [心] [给力] [神马] [围观] [奥特曼] more »