今天来谈谈闭包,不从晦涩难懂的文字来谈,直接用简单的代码,了解闭包到底大概是什么样子的,我们平时又怎么用到它。
了解闭包,我们首先要知道函数的作用域,它有一个特点,就是与调用时所在的作用域无关,只跟定义的所在的作用域有关,也就是从函数被写好时就固定了。
严格来讲,所有函数都是闭包。
但是因为我们平时写代码最多的状态,函数定义所在的作用域和函数调用时所在的作用域是一个作用域,所以闭包没什么讨论的意义。
下面是非常简单的例子,我们很容易得出,结果是out
。
let n = 'out'
// 函数定义时
let outFunc = () => {
console.log(n)
}
// 函数调用时
outFunc() // out
假如我们嵌套了一个函数在内部,下面例子我们可以得到什么结论呢?
虽然我们的函数是在外部调用的,但是我们函数中输出结果变量n
是内部函数定义时所在的变量作用域中的n
。
这就是闭包值得讨论的东西。
let n = 'out'
let outFunc = () => {
let n = 'in'
// 函数定义时
return () => {
console.log(n)
}
}
// 函数调用时
outFunc()() // in
我们知道了闭包的价值存在于函数中嵌套着另一个函数时,内部的函数可以访问外部函数内的局部变量,它有什么用呢?
我们先来看看这个例子,这个例子实现了函数执行对于某个变量的计数自增。
let count = 0
let add = () => {
console.log(count++)
}
add() // 0
add() // 1
add() // 2
这段代码存在一个问题,就是count
太容易被人修改了,这样的自增并不安全。
我们如何让count不会被人意外修改呢?让它成为私有变量。
我们就可以借用闭包的思想。
let add = (() => {
let count = 0
return () => {
console.log(count++)
}
})()
add() // 0
add() // 1
add() // 2
当外部的函数add在外部被定义出来的那一刻,内部函数所使用的局部变量count
已经处于只有它可以访问的状态,属于它的私有变量。
但是我们发现我们上面写的这种私有状态没办法复用,因为我们的add
定义时就被调用,内部的私有状态只被一个闭包独享。
我们可以使用一个外部函数定义多个闭包,达到复用私有状态的目的:
let add = () => {
let count = 0
return () => {
console.log(count++)
}
}
let add1 = add()
let add2 = add()
add1() // 0
add1() // 1
add2() // 0
add2() // 1
还有局部的私有变量我们可以提升到入参位置,达到设置初始值的目的,除了定义时,后续也是不可修改的。
let add = (count) => {
return () => {
console.log(count++)
}
}
let add1 = add(0)
let add2 = add(100)
add1() // 0
add1() // 1
add2() // 100
add2() // 101
综上,我们可以简单的做个总结,一个内部的函数被定义在一个外部的函数中,就可以将外部函数的变量作为自己的私有变量。
继续用一个例子加深理解,只要是内部的函数被定义时就可以了,即便这个函数是某个对象上的方法也可以。
let obj = {}
let addPrivateCount = (obj) => {
let count = 0
obj.getCount = () => {
console.log(count++)
}
}
addPrivateCount(obj)
obj.getCount() // 0
obj.getCount() // 1
obj.getCount() // 2
console.log(obj) // { getCount: [Function (anonymous)] }
我这里顺便输出了obj
,告诉你上面只存在一个获取count
的方法,但是并没有count
变量,count
可以算作它私有的变量,虽然可以获取,但是除了它的getCount
方法访问,没有别的办法访问。
如果能够读懂这些小例子,相信闭包已经难不到你了,而且你也能够利用闭包去解决实际编程中的一些问题。
如果本文对你有帮助的话,欢迎点赞收藏,有什么意见或问题也欢迎提出,感谢~