首页 > JavaScript 阅读:16106

JS闭包的原理和作用

通义灵码
闭包(closures)是 Javascript 语言的一个难点,也是它的特色,很多高级应用都是依靠闭包实现的。闭包与变量的作用域以及变量的生命周期密切相关,本节我们就来简单介绍一下。

什么是闭包

所谓闭包,指的就是一个函数。当两个函数彼此嵌套时,内部的函数就是闭包。

因为在 JavaScript 中,函数属于对象,对象又是属性的集合,而属性的值又可以是对象,所以我们可以在函数内部再定义函数。例如在函数 A 中定义了函数 B,然后在函数外部调用函数 B,这个过程就是闭包。

闭包的形成条件是内部函数需要通过外部函数 return 给返回出来,如下例所示:
  1. function funOne(){ // 外部函数
  2. var num = 0; // 局部变量
  3. function funTwo(){ // 内部函数
  4. num++;
  5. return num;
  6. }
  7. return funTwo;
  8. }
  9. var fun = funOne(); // 返回函数 funTwo
以上代码就构成了一个闭包,其实就是函数 fun。

闭包的用途

在介绍闭包的作用之前,我们先来了解一下 JavaScript 中的 GC(垃圾回收)机制。

在 JavaScript 中,如果一个对象不再被引用,那么这个对象就会被 GC 回收,否则这个对象会一直保存在内存中。在上面的例子中,内部函数 funTwo() 定义在外部函数 funOne() 中,因此 funTwo() 依赖于 funOne(),而全局变量 fun 又引用了 funTwo(),所以 funOne() 间接的被 fun 引用。因此 funOne() 不会被 GC 回收,会一直保存在内存中,如下例所示:
  1. function funOne(){
  2. var num = 0;
  3. function funTwo(){
  4. num++;
  5. console.log(num);
  6. }
  7. return funTwo;
  8. }
  9. var fun = funOne();
  10. fun(); // 输出:1
  11. fun(); // 输出:2
  12. fun(); // 输出:3
  13. fun(); // 输出:4
num 是外部函数 funOne() 中的一个变量,它的值在内部函数 funTwo() 中被修改,函数 funTwo() 每执行一次就会将 num 加 1。根据闭包的特点,函数 funOne() 中的变量 num 会一直保存在内存中。

当我们需要在函数中定义一些变量,并且希望这些变量能够一直保存在内存中,同时不影响函数外的全局变量时,就可以使用闭包。

闭包的高级用法

上面介绍的是闭包最原始的写法,在实际开发中,通常会将闭包与匿名函数结合使用,如下例所示:
  1. var funOne = (function(){
  2. var num = 0;
  3. return function(){
  4. num++;
  5. return num;
  6. }
  7. })();
  8. console.log(funOne()); // 输出:1
  9. console.log(funOne()); // 输出:2
  10. console.log(funOne()); // 输出:3
此外,同一个闭包机制可以创建多个闭包函数出来,它们彼此没有联系,都是独立的,如下例所示:
  1. function funOne(i){
  2. function funTwo(){
  3. console.log('数字:' + i);
  4. }
  5. return funTwo;
  6. };
  7. var fa = funOne(110);
  8. var fb = funOne(111);
  9. var fc = funOne(112);
  10. fa(); // 输出:数字:110
  11. fb(); // 输出:数字:111
  12. fc(); // 输出:数字:112