# 闭包恍然大悟

原文地址：<https://www.cnblogs.com/xxcanghai/p/4991870.html>

## 闭包最重要的一个作用就是把某些变量隐藏起来，让外面的程序不能直接访问。只要不是为了这个目的的闭包都可以取消。当然有时候为了组织代码，也会用闭包来进行一下封装，给代码分段，毕竟如果不用模块管理库的话，就会把很多模块都写在一个文件里，看起来确实痛苦。

闭包呢，说起来也了解了，但是现在在工作中也不知道用到了没，有没有造成内存泄漏。所以，我还是没认识到闭包，因为我不知道什么时候用，为什么用，会有什么好处，造成什么影响？

对于闭包的简单描述：

* 在函数里嵌套函数
* > 父函数 return 子函数\
  > function par (){
  >
  > var a = 0 ;
  >
  > retrun function child(){
  >
  > a++;
  >
  > console.log(a);
  >
  > retrun a ;
  >
  > }
  >
  > }
* > 通过父函数调用了子函数。\
  > var child = par();
  >
  > child();

## 重点来了：

闭包里函数可以访问外部函数的作用域，即子函数可以访问父函数里的变量，当这个子函数被调用，而且这个子函数又引用了父函数的变量，所以父函数的作用域不会被回收，也就是说父函数里的a一直存在。有的时候，我要在一个点击事件里，通过点击的次数是偶数还是奇数来做不同的操作。肯定得有一个变量保存点击的次数。我一般会用一个全局变量来保存点击次数。之前也想到过，用闭包里父函数作用域里的变量保存点击次数，用子函数来改变量的次数。于是\*\*

```javascript
$btn.click(function(){
    var count = par()();
    console.log(count);
    if(count%2==0){
        alert("我是偶数");
    }else{
        alert("我是奇数");

    }
});
```

```
但是每次输出的count都是1；也就是每次都是从0开始加。不是说闭包里不会回收变量的吗？
```

其实一想，每次点击的时候 par()();不就是每次都调用了父函数，在调用的子函数，这样当然每次都会执行复函数里的 a = 0；从而在执行子函数是是从0开始加起来的。**要是不调用父函数，我也得不到子涵呀？于是干脆还是用全局变量得了。**

**今天才理解到，先把子函数用变量保存起来，再调用。难怪那些讲解闭包的文章里都是把子函数先用变量接收！**

```
var changeStatus = par();
$btn.click(function(){
    var count = changeStatus();
    console.log(count);
    if(count%2==0){
        alert("我是偶数");
    }else{
        alert("我是奇数");

    }
});
```

**现在闭包里的变量没被GC——垃圾回收的状态实现了 ，可是又让我理解的头晕的是，用变量接收的子函数，每次在调用的时候怎么不也是调用了父函数？变量到底是个什么东西，保存赋值后发生了什么这么神奇的事。用变量接收的 var changeStatus = par(); 和 直接的 par () ; 不是同一个东西吗？要说是构造函数每次 new 出来的实例，那的确是不一样，每一个都是新的对象。这样用变量保存的子函数是和构造函数的实例是一回事吗？**

我又专门打印了一下这个用变量接收的子函数，确实只有子函数的部分。我倒也是理解，如果直接 child()调用子函数是报错的。因为这样直接调用是在wido作用域下调用，也就是找不到这个子函数。那可以这样理解：通过父函数返回的这个子函数让变量 changeStatus 引用到了子涵数，也就是找到了这个子函数，所以每次调用变量，都是可以调用这个子函数，根据闭包的原理，可以访问到父函数的作用域，使父函数不被回收。

到现在对闭包的了解深了一些，不过关于用变量保存的子函数，与有直接调用父函数 par()返回的子函数之间有什么不同，还是模糊。并且有意思的是。用变量子函数changeStatus() 改变父作用域里的变量后，再直接通过父函数返回子函数调用子函数 par()()，居然对changeStatus() 的结果没影响,再调用changeStatus()，还是接着它上一次的结果。仿佛每次par()()都重新创建了一个作用域。父作用域不都是来自 pa r函数吗 ？


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://sekin.gitbook.io/myjs/nei-cun-de-na-xie-shi/bi-bao-huang-ran-da-wu.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
