什么是闭包
想必用过js的朋友都知道,js的函数作用域,提到函数作用域,就不得不提js的闭包了,那到底什么是闭包呢?既然要在解释一下,去百度复制粘贴就没意思了,我就通俗的解释一下。说白了,就是垃圾回收机制没有及时回收的“垃圾”,还是上代码:
function fun () {
var a = 1;
function fn() {
console.log(a) // 1
}
}
fun ()
看了上面这段代码,有些人会说这和闭包有什么关系呢?的确一开始我对闭包的概念没那么了解的时候也有同样的看法,但是随着对闭包理解的深入就明白了,其实在函数fn手里拿着拿着变量a在fn没执行之前a是不会被回收机制回收掉的,这就是闭包。
闭包无处不在
说起闭包好像高大上的样子,其实在我们写代码的过程中,闭包几乎是无处不在的,上代码:
<html>
<head>
...
</head>
<body>
<button>你点我呀</button>
<script>
var oBtn = document.getElementsByTagName('button')[0]
function bindClick () {
var a = 0
oBtn.onclick = function () {
alert(a++)
}
}
bindClick()
</script>
</body>
</html>
这时候,每点一下按钮都会弹出a的值,这个a为什么会一直都在呢? 就是因为js中的垃圾回收机制,知道这个a还有要用到的时候,所以并没有将其回收。如果把代码改成:
<html>
<head>
...
</head>
<body>
<button>你点我呀</button>
<script>
var oBtn = document.getElementsByTagName('button')[0]
function bindClick () {
var a = 0
alert(a)
}
bindClick()
</script>
</body>
</html>
那么当bindClick()执行完之后a就会被回收掉。
一个例子
这里举一个很经典的例子:
<html>
<head>
...
</head>
<body>
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<script>
var oBtn = document.getElementsByTagName('button')
function fun () {
for (var i = 0; i < oBtn.length; i++) {
oBtn[i].onclick = function () {
console.log(i)
}
}
}
fun()
</script>
</body>
</html>
上面这段代码中当点击每个按钮之后控制台会输出什么呢?答案是:无论点击哪个按钮输出的都是3,这是为什么呢?这就是闭包很要命的一个特点,也可以说是js很要命的一点,for循环的时候每一次循环 i 都会加1但是,这时候 i 的值就会把上一次的覆盖掉,当循环完之后,console.log(i)的 i 就会向for循环的var i 要值而这时候的值是3所以无论点击哪个按钮,所打印出来的值都是3。说起来这好像不是闭包的错,好像的确不是,但是在没有块级作用域的情况下倒是可以通过闭包解决这个问题:
var oBtn = document.getElementsByTagName('button')
function fun () {
for (var i = 0; i < oBtn.length; i++) {
(function (i) {
oBtn[i].onclick = function () {
console.log(i)
}
})(i)
}
}
fun()
代码经过这样的改动后,当即按钮1就会输出0按钮2输出1…这又是为什么呢?说起来还是js没有块级作用域惹得祸,改动之后每次循环绑定点击事件的时候,都会创建一个全新的函数作用域,所以每一次都会声明一个独立的 i 在自执行函数执行时通过参数传递进去。
当然如果是es6的话有更容易的解决方法
var oBtn = document.getElementsByTagName('button')
function fun () {
for (let i = 0; i < oBtn.length; i++) {
oBtn[i].onclick = function () {
console.log(i)
}
}
}
fun()
嘻嘻是不是很简单呢,不过这不是今天要说的话题。
闭包的危害
说起危害呀,最大的就是容易造成内存泄漏,不会受的变量越多,对系统造成的压力也就越大,自然就影响性能咯。好今天就这样,打好收工。