前言
JavaScript 闭包笔记,闭包在我看来只是一个噱头,实际用处肯定不大。因为在我看来,语法容易理解的东西拼接成复杂也好简单也好的逻辑才是程序该有的样子,而闭包只有有点绕,但是自己推敲下,发现不过也就是这么回事的东西
此文结合菜鸟驿站的计数器问题做个笔记
引
如果想在JS中设计一个全局计数器,可以写如下方法
1 | var counter = 0; |
这个写法很简单,但是缺点也很明显,counter作为全局变量暴漏在外,不是一个优秀的设计习惯,那如果在函数内部声明counter呢?不用想就知道不行,那样每次调用函数都会初始化一次,遍无法计数
1 | function add() { |
所有函数都能访问全局变量。
实际上,在 JavaScript 中,所有函数都能访问它们上一层的作用域。
JavaScript 支持嵌套函数。嵌套函数可以访问上一层的函数变量。
那么如果设计一个嵌套函数,外层初始化counter,内层累加,问题就解决了,提前是外部可以直接调用嵌套函数
1 | function add() { |
如果我们能在外部访问 plus() 函数,这样就能解决计数器的困境。
我们同样需要确保 counter = 0 只执行一次。
我们需要闭包。
闭包
菜鸟驿站直接给出了实现了闭包代码如下
1 | var add = (function () { |
变量 add 指定了函数自我调用的返回字值。
自我调用函数只执行一次。设置计数器为 0。并返回函数表达式。
add变量可以作为一个函数使用。非常棒的部分是它可以访问函数上一层作用域的计数器。
这个叫作 JavaScript 闭包。它使得函数拥有私有变量变成可能。
计数器受匿名函数的作用域保护,只能通过 add 方法修改。
我觉得这段代码有点太故弄玄虚了,让人一眼看上去觉得很难理解,我按照自己的思路分析一下从嵌套到闭包的过程
1 | function add() { |
这是之前的嵌套函数,他的问题在于外部无法调用plus()方法,我将其改成返回plus()方法
1 | function add() { |
就变成这鸟样了,但是plus方法没有返回值,我想要的counter,所以再改一下,让plus方法返回counter+1
1 | function add() { |
注意,这个时候闭包已经实现了,为什么这么说呢?
- add()方法中初始化了counter,返回了plus()方法,这样外部可以直接调用plus()方法
- plus()可以直接实现累加,他不会再去初始化一遍counter了
这段代码调用如下:
1 | function add() { |
简化一下代码,不要plus名字了,返回匿名方法
1 | function add() { |
每次手动初始化一遍太麻烦,利用函数的自我调用再次修改一下代码就变成了最终版
1 | var add = (function() { |
后记
- 闭包就是利用嵌套函数,外层初始化变量,内层处理变量,然后外层返回内层方法
- JS特性就是这种情况下,虽然是函数内的变量,但是函数结束不会被回收,因为返回的嵌套函数仍然会用到它,从而巧妙的隐藏了变量在函数内
- 论私有的重要性