闭包
闭包的产生
当一个内部函数调用外部函数的变量(函数)时,就产生了闭包。闭包是包含被引用数据的对象。因此闭包产生的条件有:
- 函数的嵌套
- 内部函数调用外部函数的数据
闭包的作用
- 使函数内部的变量在函数执行完后仍然存活,延长了局部变量的生命周期。
- 使得函数外可以读写和操作函数内部的变量。
闭包的生命周期以及缺点
闭包在嵌套内部函数定义执行完时就产生了,闭包在调用后不会自动释放,需要手动使其变为垃圾对象再被程序释放。(手动释放一般是将变量指向null)
由于闭包的特点,函数执行完后, 函数内的局部变量没有释放, 占用内存时间会变长,容易造成内存泄漏。
内存泄漏和内存
闭包产生,作用,生命周期实例
function fn1 () {
//此时闭包就已经产生了
var a = 1;
function fn2 () {
a++;
console.log(a);
}
//返回fn2使得外部可以调用
return fn2;
}
//现在的fn即function fn2
var fn = fn1();
//通过调用fn操作a
fn();//2
fn();//3
//使得fn成为垃圾对象,闭包会被释放
fn = null;
闭包的实际应用
定义一个具有特定功能的JS文件(JS模块),将所有的数据和功能都封装在一个函数内部(私有的),只向外暴露一个包含n个方法的对象或函数。模块的使用者只需要通过模块暴露的对象,来调用相应的方法实现对应的功能。
//js模块:
function test() {
//私有数据
var msg = 'hello';
var names = ['mike','john'];
//操作私有数据的函数
function doSomething() {
console.log(msg)
}
function doOtherthing() {
console.log(names.join())
}
//向外暴露包含多个方法的对象
return {
doSomething: doSomething,
doOtherthing: doOtherthing
}
}
//引用js模块的文件
//首先进行相关模块的引用
<script src="test.js"></script>
<script type="text/javascript">
//获得对象
var module = test()
//通过获得的对象中暴露的方法操作内部的数据
test.doSomething()
test.doOtherthing()
</script>
除了这种获得对象,调用方法的操作还可以将js模块中的函数设为自调用函数,然后在window上直接添加对象,这样在调用的时候就不用接收,可以直接通过window来调用。
练习
//example1
var name = "window";
var object = {
name: "obj",
getName: function () {
return function () {
return this.name;
};
}
};
console.log(object.getName()()); //window
//example2
var name2 = "window";
var object2 = {
name2: "obj",
getName: function () {
//产生了闭包
var that = this;
return function () {
return that.name2;
};
}
};
console.log(object2.getName()()); //obj
example1:object.getName()返回的是function () {return this.name},
因此object.getName()()相当于在全局作用域下直接调用function () {return this.name},即window。
example2:object.getName()()相当于直接调用function () {return that.name2},由于产生了闭包,that指代object2这个对象,因此返回object2.name2,即obj。