下面我们来看一个闭包函数的应用,前面我们讲过图和给元素批量绑定事件。
如果我们使用for循环来实现它会产生一个变量丢失的问题,这时如果使用闭包就能解决这个问题,当然,在es6中,只要用let声明变量也可以解决该问题。
这里只是为了说明闭包的意义,请看下面的代码:
<!DOCTYPE html>
<html>
<head>
<title>变量的作用域始终是变量定位的位置</title>
<script src="./jquery.js"></script>
</head>
<body>
<ul>
<li>li1</li>
<li>li2</li>
<li>li3</li>
<li>li4</li>
<li>li5</li>
</ul>
<script type="text/javascript">
var lis = document.querySelectorAll('li');
for(var i=0; i<lis.length; i++){
lis[i].onclick = function(){
//输出 我是第 几 个li标签
console.log('我是第 ' + i + ' 个li标签');
}
}
</script>
</body>
</html>
通过上面的实验我们看到,我们使用for循环给所有的li标签分别绑定了点击事件,但是,当我们点击每一个li标签时,它们获取到变量i都是同一个值:5,这就有点尴尬了。
下面我们用闭包试试看
<!DOCTYPE html>
<html>
<head>
<title>变量的作用域始终是变量定位的位置</title>
<script src="./jquery.js"></script>
</head>
<body>
<ul>
<li>li1</li>
<li>li2</li>
<li>li3</li>
<li>li4</li>
<li>li5</li>
</ul>
<script type="text/javascript">
var lis = document.querySelectorAll('li');
for(var i=0; i<lis.length; i++){
//套一层匿名函数自调用,形成了一个闭包环境
//主要作用是形成一个局部作用域
(function(m){
lis[m].onclick = function(){
console.log('我是第 ' + m + ' 个li标签');
}
})(i);//每次循环就把i传入,这样每次调用都会得到一个独立的作用域,等同于循环了5次,创建了5个局部作用域。
}
</script>
</body>
</html>
这样就将i的值全部保存了下来。
当然,在ES6中根本不需要这么复杂,我们使用let声明i变量即可解决,如下:
<!DOCTYPE html>
<html>
<head>
<title>变量的作用域始终是变量定位的位置</title>
<script src="./jquery.js"></script>
</head>
<body>
<ul>
<li>li1</li>
<li>li2</li>
<li>li3</li>
<li>li4</li>
<li>li5</li>
</ul>
<script type="text/javascript">
var lis = document.querySelectorAll('li');
for(let i=0; i<lis.length; i++){
lis[i].onclick = function(){
console.log('我是第 ' + i + ' 个li标签');
}
}
</script>
</body>
</html>
同样得到了闭包实现的结果。
还是那句话,闭包主要解决的是:为了防止命名冲突而使用匿名函数包裹一堆代码,从而形成一个封闭的空间,当我们想在匿名函数外部使用匿名函数内部的变量时,就把匿名函数的作用域返回给外部。
以上案例并非闭包函数的初衷,仅是一个巧用而已。
|