定义:通俗讲,闭包是函数里面再定义一个函数,里层函数能访问到外层函数的局部变量,也就是说闭包是一个能访问外层函数局部变量的函数。常用情景有以下3种。
1.在window下有个全局变量a,在函数checkScope内部有个局部变量a。需求:在window下调用函数checkScope达到返回函数checkScope内部局部变量a的值。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
var a = '全局变量';
function checkScope() {
var a = '局部变量'
function f() {
return a;
}
return f();
}
console.log(checkScope()); //局部变量
</script>
</body>
</html>
2.页面有很多li元素,点击每一个li获取到该li标签的索引index。
如下代码并不能获取到点击的li的索引。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<ul>
<li>这是第一个li</li>
<li>这是第二个li</li>
<li>这是第三个li</li>
<li>这是第四个li</li>
<li>这是第五个li</li>
</ul>
<script>
var li = document.getElementsByTagName('li');
for (var i = 0, len = li.length; i < len; i++) {
li[i].onclick = function () {
console.log(i); //5
}
}
</script>
</body>
</html>
使用闭包可以实现该需求
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<ul>
<li>这是第一个li</li>
<li>这是第二个li</li>
<li>这是第三个li</li>
<li>这是第四个li</li>
<li>这是第五个li</li>
</ul>
<script>
var li = document.getElementsByTagName('li');
for (var i = 0, len = li.length; i < len; i++) {
(function (i) {
li[i].onclick = function () {
console.log(i);
}
}(i))
}
</script>
</body>
</html>
3.提高函数性能,将结果保存,不需要将结果暴露在window的全局变量中。例如计算阶乘,如果以前有计算过,那么直接从以前的结果中获取,不需要重新计算。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
var mult = (function () {
var cache = {};
var calculate = function () {
var a = 1;
for (var i = 0, len = arguments.length; i < len; i++) {
a = a * arguments[i];
}
return a;
}
return function () {
var args = Array.prototype.join.call(arguments, ',');
if (args in cache) {
return cache[args];
}
return cache[args] = calculate.apply(null, arguments);
}
}())
</script>
</body>
</html>