闭包:函数嵌套+内部函数引用了外部函数的变量
一、闭包的声明周期
- 产生:在嵌套的内部函数定义执行完时就产生了(不是在调用)
- 死亡:在嵌套的内部函数成为垃圾对象时
function fn1() {
// 此时闭包就已经产生了(函数提升,内部函数对象已经创建了)
var a = 2;
function fn2() {
a++;
console.log(a);
}
return fn2;
}
var f = fn1();
f(); //3
f(); //4
f = null; // 闭包死亡(包含闭包的函数对象成为垃圾对象)
// 3-6行执行完才会产生闭包。
1. fn1() {
2. var a = 2;
3. var fn2 = function() {
4. a++;
5. console.log(a);
6. }
7. return fn2;
8. }
9. var f = fn1();
f(); //3
f(); //4
f = null; // 闭包死亡(包含闭包的函数对象成为垃圾对象)
二、闭包的应用——自定义js模块
定义js模块:
- 具有特定功能的js文件
- 将所有数据和功能都封装在一个函数内部(私有的)
- 只向外暴露一个包含n个方法的对象或函数
- 模块的使用者,只需要通过模块暴露的对象调用方法来实现对应的功能
(一)
function myModule() {
// 私有数据
var msg = 'hahaha';
// 操作数据的函数
function doSomething() {
console.log('doSomething' + msg.toUpperCase());
}
function doOtherthing() {
console.log('doOtherthing' + msg.toLowerCase());
}
// 向外暴露对象(给外补使用的方法)
return {
doSomething: doSomething,
doOtherthing: doOtherting
}
}
var module = myModule();
module.doSomething();
module.doOtherthing();
(二)
(function() {
// 私有数据
var msg = 'hahaha';
// 操作数据的函数
function doSomething() {
console.log('doSomething' + msg.toUpperCase());
}
function doOtherthing() {
console.log('doOtherthing' + msg.toLowerCase());
}
window.myModule2 = {
doSomething: doSomething,
doOtherthing: doOtherting
}
})()
myModule2 .doSomething();
myModule2.doOtherting();
三、闭包的缺点及解决
- 缺点:
- 函数执行完后,函数内的局部变量没有释放,占用内存时间会变长
- 容易造成内存泄漏
- 解决:
- 能不用闭包就不用
- 及时释放
function fn1() {
var arr = new Array(1000000);
function fn2() {
console.log('111');
}
return fn2;
}
var f = fn1();
f();
f = null; // 让内部函数成为垃圾对象=>回收闭包
内存溢出与内存泄漏
- 内存溢出
- 一种程序运行出现的错误
- 当程序运行需要的内存超过了剩余的内存时,就会抛出内存溢出的错误
- 内存泄漏
- 占用的内存没有及时释放
- 内存泄漏积累多了就容易导致内存溢出
- 常见的内存泄漏
(1)意外的全局变量
(2)没有及时清理的计时器或回调函数
(3)闭包
// 1. 内存溢出
var obj = {};
for (var i = 0; i<10000; i++) {
obj[i] = new Array(10000000);
console.log('111');
}
// 2. 内存泄漏
// 意外的全局变量
function fn() {
a = 1;
console.log(a);
}
fn();
// 启动循环定时器不清理
var interval = setInterval(function() {
console.log('111');
}, 1000)
// clearInterval(interval);
// 闭包
function fn1() {
var arr = new Array(1000000);
function fn2() {
console.log('111');
}
return fn2;
}
var f = fn1();
f();
// f = null;
四、测试题
测试题1:
var name = 'aaa';
var object = {
name: 'bbb';
getNameFunc() {
return function() {
return this.name;
};
}
};
console.log(object.getNameFunc()()); // aaa
var name = 'aaa';
var object = {
name: 'bbb';
getNameFunc() {
var that = this;
return function() {
return that.name;
};
}
};
console.log(object.getNameFunc()()); // bbb