闭包是什么

闭包是用来解决全局变量私有化的,也可以说成局部变量全局化。全局变量所有脚本都可以用,局部变量只能局部使用,外部不能使用。那如果一个全局变量,我想让某个函数使用,别人不能使用,怎么办?

有人可能会说,那就声明成局部变量呗。局部变量每次调用的时候,都会重新声明赋值。而我是想让局部变量像全局变量一样,只声明赋值一次。

比如,我想做个计数器。点击一下加1。听起来很简单。代码如下:

<button type="button" onclick="add()">计数</button>
<p id="demo">0</p>
<script>
var counter = 0;

function add(){
document.getElementById("demo").innerHTML = ++counter;
}
</script>

上面的代码实现了想要的功能。但是,有一个安全隐患。变量counter除了函数add可以更改,其他任何代码都可以改变counter的值。

闭包做法

安全的做法是,只有函数add可以更改counter的值。就像有人提出的一样。把counter改成局部变量。那代码如下:

<button type="button" onclick="add()">计数</button>

<p id="demo">0</p>

<script>
function add(){
var counter = 0;
document.getElementById("demo").innerHTML = ++counter;
}
</script>

这样的话,解决了counter不被别人修改的风险了,但是,我们的功能有问题了,点击输出的永远是1了。每次调用add,都重新声明了一个新变量counter并且赋值为0。

如果,var counter = 0;这一句只执行一次就好啦!

修改

还记得之前介绍函数的时候,函数有一种调用方式叫自调用。自调用是只执行一次的。我们可以利用它来搞定。代码如下:

<button type="button" onclick="doAdd()">计数</button>

<p id="demo">0</p>

<script>
var add = (function () {
var counter = 0;
return function () {counter ++; return counter;}
})();
function doAdd(){
document.getElementById("demo").innerHTML = add();
}
</script>

变量 add 的赋值是自调用函数的返回值。这个自调用函数只运行一次。解决了刚刚执行多次的问题。它设置counter为零,并返回函数表达式。add 成为了函数。它能够访问父作用域中的counter。

这叫做 JavaScript 闭包。它使函数拥有私有变量成为可能。counter被这个匿名函数的作用域保护,并且只能使用 add 函数来修改。闭包是一种保护私有变量的机制,在函数执行时形成私有的作用域,保护里面的私有变量不受外界干扰。

简化

其实,还有一种办法可以解决全局变量安全的问题。之前我们介绍过块作用域,我们可以把开始的代码放到一个块里,就可以完美解决啦!代码如下:

<button type="button" onclick="add()">计数</button>

<p id="demo">0</p>

<script>
{
let counter = 0;

function add(){
document.getElementById("demo").innerHTML = ++counter;
}
}
</script>

注意,块作用域声明变量用let。

参考链接

什么是js闭包,它能解决什么问题,这些知识你都知道吗?