浅谈JavaScript闭包

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅谈JavaScript闭包相关的知识,希望对你有一定的参考价值。

 一、背景知识

在介绍闭包之前,我觉得有必要先简单的介绍一些背景知识,如变量的作用域、嵌套函数、垃圾回收机制等概念。

1、作用域

作用域是程序运行时变量可被访问的范围,定义在函数内的的变量是局部变量,局部变量的作用域只能是函数内部范围内,它不能在函数外引用。定义在模块最外层的的变量是全局变量,它是全局范围内可见的,当然在函数里面也可以读取到全局变量的。 

var a = 123; //全局变量
function fun(){
    var b = 456; //局部变量
}

 2、嵌套函数 

函数不仅可以定义在模块的最外层,还可以定义在另外一个函数的内部,像这种定义在函数里面的函数称之为“嵌套函数”。如下所示: 

1 function foo(){
2     function goo() {
3         alert(123);
4     }
5     goo();
6 }

 3、垃圾回收机制GC

javascript具有自动垃圾回收机制(GC:Garbage Collecation),也就是说,执行环境会负责管理代码执行过程中使用的内存。原理:垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存。
GC在回收内存时,首先会判断该对象是否被其它对象引用。在确定没有其它对象引用便释放该对象内存区域。

  

二、什么是闭包Closure

关于闭包,“官方”的解释是:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。相信很少有人能直接看懂这句话,因为它描述的太学术。

其实,理解闭包的含义并不难。接下来,我将用JavaScript创建一个闭包来帮助你理解什么是闭包,因为作为程序员,有时候,看代码来理解一个知识点会比你看文字定义来理解更加容易。

function A(){
    var foo = 123;
    function B(){
        alert(foo);
    }
    return B;
}
var c = A();
c();

 上面代码翻译成自然语言如下: 

(1)定义了一个普通函数A
(2)在A中定义了普通函数B
(3)在A中返回B(确切的讲,在A中返回B的引用)
(4)执行A(),并把A的返回值赋给变量 c
(5)执行 c()

把上面这五个步骤总结一下就是:函数A的内部函数B被函数A外的一个变量 c引用;

把这句再加工一下就变成了闭包的定义:当一个内部函数被其外部函数之外的变量引用时,就形成了一个闭包。 

也可以这样说:闭包是指有权访问另一个函数作用域中的变量的函数。

 

三、闭包的作用

其实,闭包与普通函数的差别在于局部变量可以在函数执行结束后仍然被函数外的代码访问。这意味着函数必须返回一个指向闭包的“引用”,或将这个“引用”赋值给某个外部变量,才能保证闭包中局部变量被外部代码访问。当然包含这个引用的实体应该是一个对象,因为在Javascript中除了基本类型剩下的就都是对象了。 

简而言之,闭包的作用就是在A执行完并返回后,闭包使得Javascript的垃圾回收机制GC不会收回A所占用的资源,因为A的内部函数B的执行需要依赖A中的变量。 

所以,当我们需要在一个模块中定义一个能一直保存在内存中但又不会“污染”全局的变量的时候,我们就可以用闭包来定义这个模块。

 

四、闭包的应用场景

1、保护函数内的变量安全。以上面第三个例子为例,函数A中foo只有函数B才能访问,而无法通过其他途径访问到,因此保护了f的安全性。

2、在内存中维持一个变量。依然如前例,由于闭包,函数A中foo的一直存在于内存中,因此每次执行c(),都会弹出内容为“123”的弹出框。

以上两点是闭包最基本的应用场景,很多经典案例都源于此。

 

五、闭包为什么不会被JS垃圾回收机制回收

在JavaScript中,如果一个对象不再被引用,那么这个对象就会被垃圾回收机制GC回收。如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。

以上面第三个例子为例:因为函数A被函数B引用,函数B又被函数A外的变量c引用,这也就是为什么函数A执行后不会被回收的原因。

 

六、总结

以上就是对闭包简单的理解,其实,关于闭包的知识点还远不止上述所讲到的这些,要想更深入的去了解闭包,就回涉及到JS的执行环境(execution context)、活动对象(activation object)以及作用域(scope)和作用域链(scope chain)的运行机制等这些概念。但是,作为一位初学者,其实暂时可以不必了解这些的。

当然,如果你还想对闭包有一个进一步的了解,可以去看一下我的另一篇博客“深入理解JavaScript闭包”。

 

参考资料:http://blog.csdn.net/hitman9099/article/details/3854171






以上是关于浅谈JavaScript闭包的主要内容,如果未能解决你的问题,请参考以下文章

浅谈JavaScript--闭包

浅谈JavaScript的闭包

浅谈JavaScript闭包this指针作用域

浅谈JavaScript闭包

浅谈JavaScript匿名函数与闭包

javaScript--浅谈闭包