- 申明在一个函数中的函数,叫做闭包函数。
- 通常状况下,在 Javascript 语言中,只有函数外部的子函数能力读取局部变量:
function f1(){var n = 999;}
console.log(n); // n is not defined
- 闭包是一种非凡的作用域:其返回的外部函数的作用域中保留着父级的变量对象和作用域连贯,所以外部函数总是能够拜访其所在的内部函数中申明的参数和变量,即便在其内部函数被销毁之后。
- 所以,在实质上,闭包就是将函数外部和函数内部连接起来的一座桥梁。
- 让内部拜访函数外部变量成为可能
- 局部变量会常驻在内存中
- 能够防止应用全局变量,避免全局变量净化
- 会造成内存透露(有一块内存空间被长期占用,而不被开释)
- 构想有此场景:输入框中内容变动须要实时申请接口以获取最新搜寻后果,如果在输出实现前输入框内容每变动一下都去申请接口,会造成很多不必要的申请,大大增加服务器压力。
- 解决思路:有变动时提早一段时间再执行 function,若在这段延迟时间内又有新变动,则从新开始提早
// 定时器期间,有新操作时,清空旧定时器,重设新定时器
var debounce = (fn, wait) => {
let timer, timeStamp=0;
let context, args;
let run = ()=>{timer= setTimeout(()=>{fn.apply(context,args);
},wait);
}
let clean = () => {clearTimeout(timer);
}
return function() {
context = this;
args = arguments;
let now = (new Date()).getTime();
if (now-timeStamp < wait) {console.log('reset',now);
// 革除定时器,并重新加入提早
clean();
run();} else {console.log('set',now);
run(); // last timer alreay executed, set a new timer}
timeStamp = now;
}
}
- 代码进一步优化:周期内有新事件触发时,重置定时器开始工夫戳,定时器执行时,判断开始工夫戳,若开始工夫戳被推后,从新设定延时定时器;退出是否立刻执行参数。
// 减少前缘触发性能
var debounce = (fn, wait, immediate=false) => {
let timer, startTimeStamp=0;
let context, args;
let run = (timerInterval) => {timer= setTimeout(() => {let now = (new Date()).getTime();
let interval = now-startTimeStamp
if(interval < timerInterval) { // the timer start time has been reset,so the interval is less than timerInterval
console.log('debounce reset',timerInterval-interval);
startTimeStamp = now;
run(wait-interval); // reset timer for left time
} else {if (!immediate) {fn.apply(context,args);
}
clearTimeout(timer);
timer=null;
}
}, timerInterval);
}
return function() {
context = this;
args = arguments;
let now = (new Date()).getTime();
startTimeStamp = now; // set timer start time
if(!timer) {console.log('debounce set',wait);
if(immediate) {fn.apply(context,args);
}
run(wait); // last timer alreay executed, set a new timer
}
}
}
- 构想有此场景:有‘搜寻’按钮,每点击一次都会从新申请接口,获取并渲染页面表格最新数据,如果短时间内间断点击按钮,仍然会造成很多不必要的申请
- 解决思路:在一段时间内只执行最初一次 function
// 定时器期间,只执行最初一次操作
var throttling = (fn, wait) => {
let timer;
let context, args;
let run = () => {timer=setTimeout(()=>{fn.apply(context,args);
clearTimeout(timer);
timer=null;
},wait);
}
return function () {
context=this;
args=arguments;
if(!timer){console.log("throttle, set");
run();}else{console.log("throttle, ignore");
}
}
}
// 减少前缘
var throttling = (fn, wait, immediate) => {
let timer, timeStamp=0;
let context, args;
let run = () => {timer=setTimeout(()=>{if(!immediate){fn.apply(context,args);
}
clearTimeout(timer);
timer=null;
},wait);
}
return function () {
context=this;
args=arguments;
if(!timer){console.log("throttle, set");
if(immediate){fn.apply(context,args);
}
run();}else{console.log("throttle, ignore");
}
}
}