凡是满足以下三个特点,都属于闭包
1、 函数嵌套函数;
2、 内部函数使用外部函数的形参和变量;
3、 被引用的形参和变量就不会被垃圾回收机制所回收;
垃圾回收机制:
调用函数时,系统会分配一定的内存空间给这个函数使用(空间大小由这个函数里声明的变量和形参决定)。调用完毕之后,这个内存空间要释放,还给系统。
var a=0
function show(){
console.log(a);
a++;
}
show()
show()
//a的空间没被释放
alert(a)//不报错,正常显示
function show(){
var a=0
console.log(a);
a++;
}
show()
show()
//a的空间被释放
alert(a)//报错 not defined
一般情况下,函数外部是无法访问函数内定义的形参和变量的。
但是当我们将内部函数调用外部函数的变量和形参时,再将内部函数作为外部函数返回值,此时执行返回值函数时,是可以访问到函数内的变量和形参的。证明,在外部函数调用完毕之后,其定义的形参和变量并没有被立即销毁掉,而是保存在内部函数里了。只要内部函数没有被销毁,内部函数就能够不断地引用外部函数的变量和形参。
闭包的作用
1、 希望一个变量常驻在内存中2.避免全局变量污染,避免声明全局变量3.可以声明私有成员;
全局变量污染:当我们在一个页面内声明了很多变量和函数在全局作用域下,当我们将多个代码合成一个代码时,有可能就出现,全局作用下的变量和函数出现重名的情况,导致整个程序崩溃。
上图中,全局变量被不断的更改,但是如果其他人想要引用整个a的话,就是一个被更改了的a。
引起为了避免这种情况的发生,我们尽量去设置局部变量
如果要实现函数内的变量一直驻留在内存中,此时就需要闭包了
立即执行函数
原理:
但是因为()的优先级是最高的,这样就会出现,括号内为空,就会报错,因此真正执行时,需要将前面的函数也加上()
更改我们第一个例子
let res=(function (){
var a=10
function show2(){
a++;
console.log(a);
}
return show2
})()
res()
res()
声明私有变量
案例:
保存变量:
将外部变量以形参的形式传入,并立即执行
优化:
闭包注意事项
内存泄漏:被闭包占用的内存,已经被永久占用了,其他人无法再使用了,也就是所谓的钉子户
上图中,window.onload和obtn.onclick就构成了一个闭包。这样obtn就会一直驻留在内存当中。就造成内存泄漏。并且对象占用的内存比较大。
解决内存泄漏:主要出现在IE浏览器
解决方式一:减少内存泄漏,在外部函数使用变量存储需要用到值
解决方式二:利用IE浏览器独有的window.onunload 当页面解构的时候触发(刷新页面,关闭当前页面),在刷新的时候就释放内存