什么是闭包?
在函数嵌套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数,我们把这个使用外部函数变量的内部函数叫做闭包。
简单理解成“定义在一个函数内部的函数”。
闭包的构成条件
1.内外2层函数
2.内部函数中使用了父函数的变量
3.外部函数返回了内部函数。
闭包的两种写法
//闭包经典
//写法1
var pathSum = (function(ccc) {
var arr = [1,2,3]
return function fds(d) {
var c = arr
c.push(d)
return arr
}
})();
console.log(pathSum(2))
console.log(pathSum(7))
console.log(pathSum(1))
// 写法2
var pathSum = function() {
var arr = [1,2,3]
return function fds(d) {
var c = arr
c.push(d)
return arr
}
};
var ssignmentMethod = pathSum()
var ssignmentMethod1 = pathSum()
//ssignmentMethod 和ssignmentMethod1互相不响应
console.log(ssignmentMethod(2))
console.log(ssignmentMethod(7))
console.log(ssignmentMethod(1))
// 释放内存
ssignmentMethod = null
代码对比
非闭包
// 记数器:
function add(){
var count = 0;
return count++;
}
console.log(add());
console.log(add());
console.log(add());
输出 0 0 0
闭包
function add(){
var count = 0;
return function(){
return count++;
}
}
var f = add();
var f = (function (){
var count = 0;
return function(){
return count++;
}
})();
console.log(f());
console.log(f());
console.log(f());
输出 0 1 2
例子解释
变量 f 的赋值是自调用函数的返回值。
这个自调用函数只运行一次。它设置计数器为零(0),并返回函数表达式。
这样 f 成为了函数。最“精彩的”部分是它能够访问父作用域中的计数器。
这被称为 JavaScript 闭包。它使函数拥有“私有”变量成为可能。
计数器被这个匿名函数的作用域保护,并且只能使用 f 函数来修改。
闭包指的是有权访问父作用域的函数,即使在父函数关闭之后。
闭包总结
闭包会使得函数中的变量都被保存在内存中,内存消耗很大;滥用闭包会造成网页的性能问题,在IE中可能导致内存泄露。
闭包使用完最后清除,将变量设置成null;界面销毁也会清除。
f=null//销毁
闭包最常用的使用案例
1.防抖(使用最新一次操作)
export default function debounce(fn,delay){ //传入所要防抖的方法或者回调与延迟时间
let timer = null
//借助闭包,使得变量timer不被回收
return function() {
//保存传入参数
let args = arguments;
//第一次timer为null,跳过该判断,执行setTimeout()
if(timer){
clearTimeout(timer)
}
timer = setTimeout(()=>{
//apply(),改变this指向,指向正在操作的组件实例,传入参数
//之所以修改this指向,是因为我们产生了闭包,
//this指向现在为undefined,所以要修改this指向
fn.apply(this, args)
},delay)
}
}
2.节流(进行第一次点击操作)
export default function throttle(fn,delay){
let flag = true
return function() {
let args = arguments;
if(!flag){
//未超过时间间隔,flag无效,不执行fn
return false
}
fn.apply(this, args)
flag = false //在时间间隔内把状态位flag设为无效(false)
setTimeout(() => {
flag = true //超过时间间隔把状态位flag设为有效(true)
}, delay)
}
}
生活重遇到感觉最简单写法
function debounce(func, wait) {
//定时器变量
var timeout;
return function () {
//每次触发scrolle,先清除定时器
clearTimeout(timeout);
//指定多少秒后触发事件操作handler
timeout = setTimeout(func, wait);
};
}
debounce(this.handleScroll, 50),