闭包
闭包官方的解释:闭包(closure)是一个函数以及其捆绑的周边环境状态(词法环境)的引用的组合。
也就是说:闭包让开发者可以从内部函数访问外部函数的作用域。
在 JavaScript 中,闭包会随着函数的创建而被同时创建。
上面这3句话是mdn的解释。太复杂了。笨笨的我理解不了。
我的理解:闭包是函数跨作用域的一种体现,函数跨作用域访问变量,就会形成闭包。
常见的是子函数访问父函数。
表现形式:内层函数访问引用外层函数中的变量
闭包的优点和缺点
优点:变量私有化,减少全局污染。
缺点:变量常驻内存,永久不被js垃圾回收机制回收。【可能】造成内存开销过大或泄漏。
下面就是一个简单的闭包
function demo1(){
let a = 1
function b1(){
return a+1
}
b1()
}
demo1()
什么时候闭包需要return
什么情况下闭包需要 return ?当我们需要使用闭包中的某一个值
比如我们需要知道某个函数被调用了多少次?
闭包的应用:一个函数被调用了多少次
function count(){
// 变量是被私有化的。外部的更改是不会对它造成影响
let num = 0
function useNum(){
// 返回的是一个数值
return ++ num
}
// 返回的是一个函数
return useNum
}
let c = count()
// 因为返回的是一个函数,因我们需要再次使用括号进行调用
console.log(c()) // 1
console.log(c()) // 2
console.log(c()) // 3
01png
闭包的应用-节流
<body>
<input type="text" >
<input type="submit" id="btn" value="点击我">
<script>
const btn = document.getElementById("btn");
btn.addEventListener('click', throttleFn(submitHandler,2500),false)
function submitHandler(){
console.log('点击了')
}
function throttleFn(func, delay) {
let begin = 0;
return function () {
let cur = new Date().getTime();
if (cur-begin>delay) {
func.apply(this, arguments)
begin=cur
}
}
}
</script>
</body>
闭包会造成内存泄漏吗?
闭包会造成内存泄漏吗? 其实闭包不一定会造成内存泄漏。
要说内存泄漏,我们就需要知道什么是内存泄漏?
内存泄漏是指:用不到的变量依然占据着内存空间,不能够被再次利用。
如递归或者方法无法结束。
在这里我们可以得出:像 num 变量就可能存在内存泄漏。
因为用不到的变量没有依然占据着内存空间。
但并不是所有的闭包都会造成内存泄漏。
像react,vue里面就用到的闭包,但是我们不能去回收。
如何清除闭包中的占据着内存的变量
function count(){
// 变量是被私有化的。外部的更改是不会对它造成影响
let num = 0
function useNum(){
// 返回的是一个数值
return ++ num
}
// 返回的是一个函数
return useNum
}
let c = count()
// 因为返回的是一个函数,因我们需要再次使用括号进行调用
console.log(c()) // 1
// 斩断 c 与 count 的联系,
// 此时浏览器的垃圾回收机制就能回收闭包中num占有的空间
c = null
闭包返回一个函数[常见面试题]
let num =10
function f1(){
let num = 0
function fn(){
num++
console.log('num的值', num)
}
// 这个时候你返回来的是一个函数
return fn
}
let ff = f1()
ff()
ff()
输出的值是: 先是1 然后是2
闭包-从函数定义的地方开始查找值
let a = 20
// 函数执行的地方
function say(){
console.log(a)
}
function sum() {
let a = 40
// 函数调用的地方
say()
}
sum() // 输出的是20
分析:先创建了一个全局变量 a =20
然后又创建了一个局部变量 a = 40
say这个函数是一个全局函数,它里面访问的应该是全局变量20;
总结:它会从函数定义的地方开始去查找值,而不是函数执行的地方开始查找值
闭包-从函数定义的地方开始查找值 [函数作为参数传递]
var a = 'hei'
// 函数定义的地方
function foo(){
var a = 'ha'
function fo(){
console.log(a)
}
// return的是一个函数
return fo
}
function fn(say){
var a = 'fn'
// 函数调用的地方
say()
}
fn(foo())
分析:这个题其实和上一个题本质上是一样的。
它会从函数定义的地方开始去查找值,而不是函数执行的地方开始查找值。
function fn(say){
var a = 'fn'
// 函数调用的地方
say()
}
这一段代码是迷惑我们的,我们只需要记住从函数定义的地方开始去查找就行
立即执行
var a = 1
function fn(){
var a =2
function f() {
a++;
console.log(a)
}
f() // 会被立即执行一次
return f // 返回的是一个函数
}
// fn() 的时候 会立即执行 f()
var x = fn()
x()
// 输出3 然后输出4
立即执行 + 闭包
var n = 10
function fn(){
var n =20
function f() {
n++;
console.log(n)
}
f() // 21
return f
}
var x = fn()
x() // 22
x() // 23
console.log(n) // 10