闭包就是能够读取其他函数内部变量的函数.
首先要讲一下就是的变量作用域.
局部变量和全局变量.
var 和 es6 中的 let 和const
var 存在变量升级
例 b //undefind
var b =3
let 只在let命令所在的代码块内有效
b //报错error
let b=3
const 声明一个只读的常量。一旦声明,常量的值就不能改变
b //undefind
const b =3
简单的闭包示例
function f1(){
var n=999;
function f2(){
alert(n); // 999
}
}
在上面的函数中f2就是一个闭包调用了函数f1内部的局部变量,在f2中 f1内部所有的局部变量对f2都是可用的,即
function f1(){
var n=999;
var B=11
function f2(){
alert(n); // 999
alert(b) //11
}}
进阶 :
在学习es6 中有这样一个函数
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6]();
函数中输出的值为10
var a=[];
for (var i = 0; i < 10; i++) {
function (i) {
a[i] = function () {
console.log(i);
};
}(i); } }
a[6](); //6
在上面A数值中的方法就是就是一个闭包函数,用匿名自执行将i赋值到成局部变量i所以a数值中的方法是调用了匿名方法中的局部变量i,
当然es6中的let 也可以实现
var a = []; for (let i = 0; i < 10; i++) { a[i] = function () { console.log(i); };
}
a[6](); //6
变量i
是let
声明的,当前的i
只在本轮循环有效,所以每一次循环的i
其实都是一个新的变量
闭包的内存泄漏问题
1. 定义:一块被分配的内存既不能使用,也不能回收。从而影响性能,甚至导致程序崩溃。
2. 起因:JavaScript的垃圾自动回收机制会按一定的策略找出那些不再继续使用的变量,释放其占有的内存。然而由于一些原因导致在这种机制下内存管理器不能正确解读JavaScript变量的生命周期,从而没有释放其内存,而也没有再被使用。
循环引用是导致以上情况的主要原因之一。
闭包实际上非常容易造成JavaScript对象和DOM对象的隐蔽循环引用。来看看下面的例子:
function bb(){
const b=document.getElementById("p1");
b.οnclick=function() {
alert(12)
}
}
以上函数bb() 中用匿名函数创建了一个闭包。
第①句:JavaScript对象element引用了一个DOM对象(其id为“div1”); JS(element) ----> DOM(div1)
第②句:该DOM对象的onclick属性引用了匿名函数闭包,而闭包可以引用外部函数example() 的整个活动对象,包括elemnt ; DOM(div1.onclick) ---->JS(element)
由此形成了JavaScript对象和DOM对象的隐蔽循环引用。
2.解决方法:
常用的解决方法就是在JavaScript代码段运行完之时将形成循环引用的JavaScript对象手动设置为空,切断引用。
修改的例子如下:\
function bb(){
const b=document.getElementById("p1");
b.οnclick=function() {
alert(12)
}
b=null
}
或者当函数a 返回了闭包函数 b,b引用了函数a中的局部变量 ,把 a 函数赋值给一个变量d ,d执行完之后不会释放a中的局部变量.
fun a(){
var c=1
return fun(){
retrun c
}
}
var d=a()
var e=d()
while (e !== '') { // process data() e = d()}
修改
fun a(){
var c=1
var b=0
return fun(){
if(b==0){
retrun c
b++
}else{
c=null //手动清空
retrun ''
}
}
}
var d=a()
var e=d()
while (e !== '' ) { // process data() e = d()}