闭包
含义:闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数
作用
- 在实际开发中,闭包最大的作用就是用来 变量私有。
- 延长父函数变量的生明周期,因为js中只要变量后期不被调用,那么就得回收
闭包的三个特性
- 子函数可以访问父函数的变量行为
- 可以延长被调用父函数变量的生命周期
- 可以扩展父函数的空间
闭包会形成作用域
分为三种类型:全局作用域;函数作用域;块作用域。
全局作用域
- 全局作用域在页面打开的时候创建,在页面关闭时销毁。
- 直接写在script标签的JS代码,都在全局作用域。在全局作用域下声明的变量叫做全局变量(在块级外部定义的变量)。
- 全局变量在全局的任何位置下都可以使用;全局作用域中无法访问到局部作用域的中的变量
函数作用域又称(局部作用域)
- 在函数作用域中可以访问全局变量,在函数的外面无法访问函数内的变量。
- 当在函数作用域操作一个变量时,它会先在自身作用域中寻找,如果有就直接使用,如果没有就向上一作用域中寻找,直到找到全局作用域,如果全局作用域中仍然没有找到,则会报错
- 调用函数时会创建函数作用域,函数执行完毕以后,作用域销毁。每调用一次函数就会创建一个新的函数作用域,他们之间是相互独立的。
块作用域
- ES6之前JavaScript采用的是函数作用域+词法作用域,ES6引入了块级作用域
- 任何一对花括号{}中的语句集都属于一个块,在块中使用let和const声明的变量,外部是访问不到的,这种作用域的规则就叫块级作用域
- 通过var声明的变量或者非严格模式下创建的函数声明没有块级作用域。
优点
- 访问其他函数内部变量
- 变量长期驻扎在内存中,不会被内存回收机制回收,即延长变量的生命周期;
- 避免定义全局变量所造成的污染
缺点
- 大量使用闭包,造成内存占用空间增大,有内存泄露的风险
闭包内存泄漏
含义:就是当已经不需要某块内存时这块内存还存在着,垃圾回收机制就是间歇的不定期的寻找到不再使用的变量,并释放掉它们所指向的内存。
存在内存泄漏问题
- 闭包函数导致的泄漏
- javaScript对象泄漏
- BOM / DOM对象泄漏
解决内存泄漏问题
- (不用循环)解除循环引用
- 将闭包引用的外部函数中活动对象清除
- js的垃圾回收机制就是为了防止内存泄漏的
在vue中解决内存泄漏
- 如果组件中使用了定时器,需要在beforeDestroy 中做对应销毁处理
- 如果在mounted/created 钩子中使用了第三方库初始化,需要在beforeDestroy 中做对应销毁处理
- 如果在mounted/created 钩子中绑定了DOM/BOM 对象中的事件,需要在beforeDestroy 中做对应解绑处理
function fun() {
var name = "monkey";
console.log(name, 123);
function fun1() { //他是个闭包函数
console.log(name, 111);//它可以访问到函数外部的变量 var name = "monkey";
//调用了 var name = "monkey";因为子函数调用了父函数的变量name的声明周期就会延长
//如果没有调用name这个变量就会被垃圾回收机制回收 这个就是js变量回收的机制
//因为产生了闭包所以父函数的内容会变大,因为毕竟里面多调用了一个子函数
//闭包的特性
// 1.子函数使用父函数变量行为
// 2.可以延长被调用父函数变量的声明周期
// 3.可以扩展父函数的空间
}
return fun1;
}
var myFunc = fun();//为什么 var myFunc = fun() fun()赋值给myFun 是因为 fun函数里面有一个子函数fun1所以得赋值
myFunc();
//打印的结果是
monkey 123
monkey 111
function fun() {
var name = "monkey";
console.log(name, 123);
function fun1() { //他是个闭包函数
//console.log(name, 111);//它可以访问到函数外部的变量 var name = "monkey";
//调用了 var name = "monkey";因为子函数调用了父函数的变量name的声明周期就会延长
//如果没有调用name这个变量就会被垃圾回收机制回收 这个就是js变量回收的机制
//因为产生了闭包所以父函数的内容会变大,因为毕竟里面多调用了一个子函数
//闭包的特性
// 1.子函数使用父函数变量行为
// 2.可以延长被调用父函数变量的声明周期
// 3.可以扩展父函数的空间
}
return fun1;
}
var myFunc = fun();//为什么 var myFunc = fun() fun()赋值给myFun 是因为 fun函数里面有一个子函数fun1所以得赋值,
myFunc();
//打印的结果是
monkey 123 fun1函数没有调用 var name = "monkey",应该是会被销毁的但是fun函数还是打印monkey 123,应为js的执行机制是从上往下执行的执行完fun函数有执行了fun1函数
function fun() {
var name = "monkey";
console.log(name, 123);
function fun1() { //他是个闭包函数
//console.log(name, 111);//fun1里面可以访问到函数外部的变量 var name = "monkey";
//调用了 var name = "monkey";因为子函数调用了父函数的变量name的声明周期就会延长
//如果没有调用name这个变量就会被垃圾回收机制回收 这个就是js变量回收的机制
//因为产生了闭包所以父函数的内容会变大,因为毕竟里面多调用了一个子函数
//闭包的特性
// 1.子函数使用父函数变量行为
// 2.可以延长被调用父函数变量的声明周期
// 3.可以扩展父函数的空间
}
return fun1;
}
fun() //如果直接调用fun()就没有办法打印到fun1里面执行的内容,所以只打印了fun()函数里面的内容
//打印的结果是
monkey 123