闭包:
简单点说,闭包就是一个临时仓库,它的作用就是将我们要用的局部变量暂时储存起来。
举例说明。
// 定义一个函数fn,其中有一个局部变量num
function fn() {
var num = 10;
}
以上例子中,我们在函数fn中定义了一个变量num,所以变量的num的作用域就局限在函数fn内部。
那么问题来了,如何在其他作用域下获取该变量?
很简单,我们只需要使用return关键字返回就可以了。
// 定义一个函数fn,其中有一个局部变量num
function fn() {
var num = 10;
return num;
}
console.log(fn()); // 10
可是这种方式有一个缺点,外部可以直接获取该变量。
问题又来了,我又想获取这个局部变量,又希望能够修改这个局部变量,并且我对这个局部变量还有一系列乱七八糟的操作,我该如何实现?
所以就有了闭包,举例说明。
// 定义一个函数fn,其中有一个局部变量num
var fn = function () {
var num = 10;
return {
// 获取变量
getNum: function () {
return num;
},
// 修改变量
setNum: function (newNum) {
num = newNum;
}
// 还可以接着定义一些对变量num乱七八糟的操作
};
};
var aaa = fn();
aaa.setNum(100);
console.log(aaa.getNum()); // 100
以上例子中,return返回了一个对象,对象里定义了一些方法,这些方法就是我们所说的闭包,我们通过闭包,将局部变量num暂时储存了起来,并且外部无法直接获取变量num。
闭包的作用就是将私有变量,封装在一个安全的环境中,外部无法直接访问。
但是闭包有一个很大缺点,也是闭包的优点,暂时储存。
一般来说,一个函数被调用结束后,会销毁他的执行上下文,这样做的目的是节省资源。
但是闭包不一样,拿上述例子来说,函数fn返回了一个对象,这个对象里包含了两个函数,这两个函数分别创建了两个作用域,而在这两个作用域中,又引用了父级作用域的自由变量,所以,一旦销毁函数fn的执行上下文,那么它闭包中的引用的自由变量也会被销毁,结果导致程序报错,所以闭包不会销毁执行上下文,而是暂时存储起来。
正是通过这种方式,闭包将变量num给暂时存储了起来,这正是闭包的优点,同时,这也是闭包的缺点,大量的使用闭包会增加资源的消耗。
闭包一般有两种表现形式。
- 闭包作为函数返回值。
- 闭包作为函数的参数。
上述例子正是闭包的第一种表现形式,也是常见的一种形式。第二种表现形式,我们称之为回调。
回调函数:
回调函数,顾名思义,回头调用的函数,也就是说该函数是在一定的条件下调用的。
举例说明。
// 定义主函数parentFunction
function parentFunction(fn) {
console.log("主函数开始执行...");
// 函数fn作为参数被传入主函数,并在主函数内执行
fn();
console.log("主函数执行完毕...");
}
// 此时函数callbackFunction为parentFunction的回调函数
var callbackFunction = function () {
console.log("回调函数开始执行...");
};
parentFunction(callbackFunction);
// 主函数开始执行...
// 回调函数开始执行...
// 主函数执行完毕...
回调函数作为参数,传入主函数内,并在主函数内的某一点执行,就好比是主函数内定义了这个回调函数,所以回调函数的本质也是闭包。
回调函数的实际应用:
- 决定权交给客户端
- 与客户端进行交互
个人学习总结,欢迎批评指正