我们首先知道闭包有3个特性:
①函数嵌套函数
②闭包就是能够读取其他函数内部变量的函数
③参数和变量不会被垃圾回收机制回收
1. 闭包的本质就是在一个函数内部创建另一个函数。
function fn() {
var name = "zs"
return function () {
return name;
}
}
var fnn = fn();
console.log(fnn());//zs
2
function fun() {
var num = 3;
return function () {//匿名函数
var n = 0;
console.log(++n);
console.log(++num);
}
}
var f = fun();
f()//1 4
f()//1 5
匿名函数作为fun的返回值被赋值给了f,
这时候相当于 f=function(){var n = 0 … },
并且匿名函数内部引用着fun里的变量num,所以变量num无法被销毁,
而变量n是每次被调用时新创建的,所以每次 f 执行完后它就把属于自己的变量连同自己一起销毁,
于是乎最后就剩下孤零零的num,于是这里就产生了内存消耗的问题
3. 定时器与闭包
//写一个for循环,让它按顺序打印出当前循环次数
for (var i = 0; i < 5; ++i) {
setTimeout(function () {
console.log(i + ' ');
}, 1000)
}
// 按照预期它应该依次输出1 2 3 4 5,而结果它输出了五次5,这是为什么呢?
// 原来由于js是单线程的,所以在执行for循环的时候定时器setTimeout被安排到任务队列中排队等待执行,
// 而在等待过程中for循环就已经在执行,等到setTimeout可以执行的时候,for循环已经结束,i的值也已经变成5,
// 所以打印出来五个5,那么我们为了实现预期结果应该怎么改这段代码呢?(ps:如果把for循环里面的var变成let,也能实现预期结果)
for (var i = 0; i < 5; ++i) {
(function (i) {
setTimeout(function () {
console.log(i + ' ');
}, 1000)
})(i)
}
// 引入闭包来保存变量i,将setTimeout放入立即执行函数中,将for循环中的循环值i作为参数传递,100毫秒后同时打印出1 2 3 4 5
// 那如果我们想实现每隔100毫秒分别依次输出数字,又该怎么改呢?
for (var i = 0; i < 5; ++i) {
(function (i) {
setTimeout(function () {
console.log('100 * i', i);
}, 100 * i)
})(i)
}
// 在这段代码中,相当于同时启动3个定时器,i*100是为4个定时器分别设置了不同的时间,同时启动,
// 但是执行时间不同,每个定时器间隔都是100毫秒,实现了每隔100毫秒就执行一次打印的效果。
/**********************************②闭包作为参数传递*****************************************/
var num = 15;
var f1 = function (x) {
if (x > num) {
console.log('闭包作为参数传递', x);
}
}
void function (f2) {
var num = 100;
f2(30)
}(f1)
//在这段代码中,函数 f1 作为参数传入立即执行函数中,在执行到f2(30)的时候,30作为参数传入fn1中,
// 这时候if(x>num)中的num取的并不是立即执行函数中的num,而是取创建函数的作用域中的num这里函数创建的作用域是全局作用域下,
// 所以
最后总结一下闭包的好处与坏处
好处
①保护函数内的变量安全 ,实现封装,防止变量流入其他环境发生命名冲突
②在内存中维持一个变量,可以做缓存(但使用多了同时也是一项缺点,消耗内存)
③匿名自执行函数可以减少内存消耗
坏处
①其中一点上面已经有体现了,就是被引用的私有变量不能被销毁,增大了内存消耗,造成内存泄漏,解决方法是可以在使用完变量后手动为它赋值为null;
②其次由于闭包涉及跨域访问,所以会
https://blog.csdn.net/weixin_43558749/article/details/90905723
网友评论