5分钟了解闭包的概念
目的:了解闭包
阅读时长: 5 分钟
来源: 整理自慕课网教程
自说自话: 我刚学前端那会儿,一直不了解闭包是什么,如今了解了一些,就来自己尝试输出一下。
张三丰教张无忌太极拳的一段剧情:
张三丰: “还记得吗?”
张无忌: “全都记得。”
张三丰: “现在呢?”
张三丰: “啊,已经忘了一大半。”
张三丰: “不坏不坏,忘得真快,那么现在呢?”
张无忌: “已经全都忘了,忘得干干净净。”
1. 从现在开始,忘了什么是闭包,因为闭包本来就是一个抽象的概念,我们只去了解它的使用场景和作用
javascript中有个作用域的概念。
- 全局作用域
- 函数作用域

关于作用域,你必须要知道的是: 作用域取决于函数定义的地方,与函数执行无关。
这句话怎么理解? 看一段代码:
看一段代码
function F1() {
var a = 100;
return function () {
console.log(a)
}
}
var f1 = F1();
var a = 200;
f1()
这段代码打印结果: 100; 我们这样来看,
F1定义的时候,作用域已经生成。

然后,把F1 赋值给 f1, 此时,f1 是一段函数,如下:
function() {
console.log(a)
}
然后,定义了一个全局变量a,在全局环境去执行f1.
注意: 作用域取决于函数定义的地方,与函数执行无关。
此时f1执行,去找a的变量,F1的局部作用域去找。
他会找到a = 100; 而不是a=200;
2. 了解了作用域,来看看闭包的使用场景
- 函数作为参数传递
- 函数作为返回值
还是刚刚的例子
function F1 () {
var a = 100;
return function () {
console.log(a)
}
}
var f1 = F1();
function F2(fn) {
var a = 200;
fn();
}
F2(f1)
// 100
由上面的例子能看到,闭包的作用是: 封装变量, 收敛权限
看一个实际的应用场景:
function isFirstLoad() {
var _list = [];
return function (id) {
if (_list.indexOf(id) >= 0) {
return false;
}else {
_list.push(id)
return true
}
}
}
var firstLoad = isFirstLoad()
firstLoad(1) // true
firstLoad(2) // true
firstLoad(1) // false
这里在isFirstLoad 里面定义了一个数组, return了一个判断是否重复的函数。
然后在全局作用域中去调用该方法,这样的好处是: 无论如何操作,都不会污染isFirstLoad()方法中的_lsit数据了。
最后在看一个生成10个a,点击每个a,打印出对应下标的例子
var a, i;
for(var i = 0; i < 10; i++ ){
a = document.createElement('a')
a.innerHTML = i + '<br>'
a.addEventListener('click', function(e) {
e.preventDefault()
alert(i)})
document.body.appendChild(a)
}
这是一个错误的写法,点击每个按钮都是10,这个原因是什么呢?
- i 定义在全局作用域
- 循环创建10个a标签,这时候,标签创建完毕,i也循环完毕。此时i = 10;
- 点击a标签,i 去 全局作用域查找,所以,无论点哪一个a,都会alert10.
修改代码:
var a, i;
for(var i = 0; i < 10; i++ ){
(function(i) {
a = document.createElement('a')
a.innerHTML = i + '<br>'
a.addEventListener('click', function(e) {
e.preventDefault()
alert(i)})
document.body.appendChild(a)
})(i)
}
- 每次循环的时候,生成一个新的自执行函数,把i 传递进去,这样每个函数都有自己的作用域。
- 点击a的时候,去自己的作用域查找,不查找全局作用域,问题得到解决。
如有不妥之处,望指出。
谢谢阅读!
我是海明月,前端小学生。
转载自:https://juejin.cn/post/6844903831747166222