所需知识点
-
闭包
- 闭包的特点:
(1) 函数内部可以引用外部的参数和变量
(2) 参数和变量保存在内存中,不会被垃圾回收机制回收(全局变量也会长期保存在内存中) - 缺点:使用不当,容易造成内存泄漏
- 全局变量和局部变量是否可以累加?
(一般情况,全局变量可以累加,而局部变量不能累加,闭包除外) - 很详细 https://segmentfault.com/a/1190000000652891
全局变量的累加: (全局变量可以累加)
<script>
var a = 1;
function b(){
a++;
alert(a);
}
b(); //2
b(); //3
</script>
-----------------------------------------------------------------
局部变量的累加: (局部变量不能累加)
<script>
function b(){
var a = 1;
a++;
alert(a);
}
b(); //2
b(); //2
</script>
-----------------------------------------------------------------
闭包中变量的累加: (闭包可以累加变量)
注意: 因为闭包常驻内存中,所以在执行完后,手动清掉
如下面: y = null; 即时清掉
<script>
function outer(){
var x=10;
return function(){ //函数嵌套函数
x++;
alert(x);
}
}
var y = outer();
y(); // y函数调用一次,结果为11,相当于outer()();
y(); // y函数调用第二次,结果为12,实现了累加
y = null;
!(注意) 因为y是全局变量,常驻内存,而y依赖于outer(),所以outer也常驻内存,不会被垃圾回收机制清掉
</script>
-
闭包在react中的使用(事件和闭包)
- 点击事件普通函数
- 点击事件闭包
点击事件:普通函数,传参
<div onClick={ (e) => this.common(e, 'anthorParams') }>点击普通函数</div>
common = (e: React.MouseEvent<HTMLDivElement>, anthor: string ): void => {
console.log(e.target);
console.log(anthor);
}
点击事件:闭包,传参
<div onClick={ this.closure('name') }>点击闭包函数</div> ----!!注意这里相当于closure('name')()
closure = (name: string) => {
console.log(name, '1'); -------------------------- 注意:‘1’只会执行一次
// 比如 let a = 1;
// 重点:闭包外层变量a能保存在内存中,是因为let a = 1执行一次就没有再从新赋为 1
// 这也就解释了上面console 1 的时候,为什么只执行了一次
return (e: React.MouseEvent<HTMLDivElement>) => { -------- e 在这里获取
console.log(e.target);
console.log(name, '2'); ------------------------- 注意:‘2’会多次执行
};
}
防抖函数 debounce
特点:延时执行,如果在延时的时间内多次触发,则从新计时
延迟执行,设置一个延迟时间a,在事件A发生时,延迟a秒执行事件A,
如果A发生后,a秒内有新的同一事件再次发生,则a从新计时(即又要再延时a秒才会触发事件A)
节流函数 throttle
特点:每隔一段时间,只执行一次
在时间a内,只执行一次函数,多次触发,也只执行一次
竖线的疏密代表事件执行的频繁程度。可以看到,正常情况下,竖线非常密集,函数执行的很频繁。而debounce(函数防抖)则很稀疏,只有当鼠标停止移动时才会执行一次。throttle(函数节流)分布的较为均已,每过一段时间就会执行一次。
debounce函数
原理:
在闭包中设置一个变量来保存setTimeout上一次的状态,有新的输入的时候,清除定时器,再开启一个新的定时器,即重新延迟执行事件
<div onClick={ this.debounce(1000) }>点击debounce函数</div>
debounce = (delay: number) => {
let timer: any = null; ---- 闭包中的状态保存在内存中,不会被垃圾回收机制清除,所以能保存上一次的状态
return () => {
if (timer) {
window.clearTimeout(timer); ----- 只要有新的输入,就清掉上一次的定义器,从新执行新的定时器
}
timer = window.setTimeout(() => {
console.log('11111111111');
}, delay);
};
}
throttle函数
原理
用闭包设置一个变量开关a,a默认为true,点击后,执行闭包
先判断a的值( 决定是否执行定时器 ),
再把a变为false(目的是为了在规定的延时时间内,再次点击,不再执行定时器 ),
delay秒后,再执行定时器,a变为true,就又会执行定时器了。
<div onClick={ this.throttle(1000) }>点击throttle函数</div>
throttle = (delay: number) => {
let isRun: boolean = true;
return () => {
if (!isRun) {
return;
}
isRun = false;
window.setTimeout(() => {
console.log('111111');
isRun = true;
}, delay);
};
}
利用时间戳,实现throttle函数
export const throttle = (fn,wait) => {
var previous = null; //记录上一次运行的时间
var timer = null;
return function(){
var now = +new Date();
if ( !previous ) {
previous = now;
}
if(now - previous > wait){
clearTimeout(timer); ----- 这里在时间到后默认会执行一次,如果不想执行,直接return即可
fn();
previous = now;
}else{
clearTimeout(timer);
timer = setTimeout(function(){
fn();
},wait);
}
}
}
let a = +new Date()
等于
let a = new Date().valueOf() ----- 返回实例对象距离时间零点对应的毫秒数
也等于
let a = new Date().getTime()
详细:https://juejin.im/entry/58c0379e44d9040068dc952f
精简:https://segmentfault.com/a/1190000008768202
完美:https://www.jianshu.com/p/f9f6b637fd6c
2019/3/26复习
throttle-Date版本:now-last>delay时,执行函数,小于时不执行,要保证第一次要执行,所以把last初始值设置为0
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id='d'>debounce防抖函数-点击</div>
<div id='t'>throttle节流函数-点击 setTime版</div>
<div id='td'>throttle节流函数-点击 Date版本</div>
<script>
window.onload = function() {
// debounce防抖函数
function debounce(t) {
let timer;
return () => {
window.clearTimeout(timer);
timer = window.setTimeout(() => {
console.log('debounce')
}, t)
}
}
function throttle(t) {
let isRun = true;
return () => {
if (!isRun) {
return;
}
isRun = false;
window.setTimeout(() => {
console.log('throttle');
isRun = true;
}, t)
}
}
function throttleDate(t) {
let last = 0; ----------------- 定义last,保存在内存中,会积累
return () => {
let now = + new Date();
if ( now - last > t) { - 大于delay时间的话,就执行函数,并把last重新赋值到执行完最新的时间
console.log('throttle-Date');
last = + new Date();
}
}
}
//点击防抖函数
const d = document.getElementById('d');
d.onclick = debounce(1000);
// 点击节流函数
const t = document.getElementById('t');
t.onclick = throttle(1000);
// 点击节流函数- Date()
const td = document.getElementById('td');
td.onclick = throttleDate(1000);
}
</script>
</body>
</html>