防抖(debounce)函数的作用是什么?有哪些应用场景,请实现一个防抖函数
- 防抖函数的作用
防抖函数的作用就是控制函数在一定时间内的执行次数。防抖意味着N秒内函数只会被执行一次,如果N秒内再次被触发,则重新计算延迟时间。
举例说明:小思最近在减肥,但是她非常贪吃。为此,与其男朋友约定好,如果10天不吃零食,就可以购买一个包(不要问为什么是包,因为包治百病)。但是如果中间吃了一次零食,那么就要重新计算时间,直到小思坚持10天没有吃零食,才能购买一个包。所以,管不住嘴的小思,没有机会买包(悲伤的故事)...这就是防抖。
不管吃没吃零食,每10天买一个包,中间想买包,忍着,等到第十天的时候再买,这种情况是节流。如何控制女朋友的消费,各位攻城狮们,get到了吗?防抖可比节流有效多了!
- 防抖应用场景
- 搜索框输入查询,如果用户一直在输入中,没有必要不停地调用去请求服务端接口,等用户停止输入的时候,再调用,设置一个合适的时间间隔,有效减轻服务端压力。
- 表单验证
- 按钮提交事件。
- 浏览器窗口缩放,resize事件等。
- 防抖函数实现
- 事件第一次触发时,
timer
是null
,调用later()
,若immediate
为true
,那么立即调用func.apply(this, params)
;如果immediate
为false
,那么过wait
之后,调用func.apply(this, params)
- 事件第二次触发时,如果
timer
已经重置为null
(即 setTimeout 的倒计时结束),那么流程与第一次触发时一样,若timer
不为null
(即 setTimeout 的倒计时未结束),那么清空定时器,重新开始计时。
function debounce(func, wait, immediate = true) {
let timer;
// 延迟执行函数
const later = (context, args) => setTimeout(() => {
timer = null;// 倒计时结束
if (!immediate) {
func.apply(context, args);
//执行回调
context = args = null;
}
}, wait);
let debounced = function (...params) {
let context = this;
let args = params;
if (!timer) {
timer = later(context, args);
if (immediate) {
//立即执行
func.apply(context, args);
}
} else {
clearTimeout(timer);
//函数在每个等待时延的结束被调用
timer = later(context, args);
}
}
debounced.cancel = function () {
clearTimeout(timer);
timer = null;
};
return debounced;
};
immediate
为 true 时,表示函数在每个等待时延的开始被调用。
immediate
为 false 时,表示函数在每个等待时延的结束被调用。
原创链接地址 :防抖(debounce)函数
节流(throttle)函数的作用是什么?有哪些应用场景,请实现一个节流函数
- 节流函数的作用
节流函数的作用是规定一个单位时间,在这个单位时间内最多只能触发一次函数执行,如果这个单位时间内多次触发函数,只能有一次生效。
举例说明:小明的妈妈和小明约定好,如果小明在周考中取得满分,那么当月可以带他去游乐场玩,但是一个月最多只能去一次。
这其实就是一个节流的例子,在一个月的时间内,去游乐场最多只能触发一次。即使这个时间周期内,小明取得多次满分。
- 节流应用场景
- 按钮点击事件
- 拖拽事件
- onScoll
- 计算鼠标移动的距离(mousemove)
/**
* 定时器版
* @param {Function} fn 需要执行的函数
* @param {Number} delay 触发时间间隔
*/
function throttle (fn, wait) {
let timeout = null
return function () {
let context = this,
args = arguments
if (!timeout) {
timeout = setTimeout(() => {
timeout = null
fn.call(context, args)
}, wait)
}
}
}
/**
*时间戳版
* @param {Function} fn 需要执行的函数
* @param {Number} wait 触发时间间隔
*/
function throttle (fn, wait) {
let pre = 0
return function () {
let now = Date.now(),
context = this,
args = arguments
if (now - pre > wait) {
fn.call(context, args)
pre = now
}
}
}
var、let、const区别
声明方式 | 变量提升 | 暂时性死区 | 重复声明 | 块作用域有效 | 初始值 | 重新赋值 |
var | 会 | 不存在 | 允许 | 不是 | 不必须 | 允许 |
let | 不会 | 存在 | 不允许 | 是 | 不必须 | 允许 |
const | 不会 | 存在 | 不允许 | 是 | 必须 | 不允许 |
作用域中声明了let变量,但是let变量的使用却在声明之前,这通常叫做变量提升。
但是let并不像var一样,var变量声明前使用,会打印出undefined.但是let变量直到被赋值才会被初始化。
在变量被初始化前访问这个变量会报reference error.我们称这个变量在作用域开始到被初始化之间为暂时性死区。
- var存在变量提升,let,const都不存在变量提升
- 暂时性死区
- 在相同作用域中,let 和 const 不允许重复声明变量,var允许重复声明变量
- const声明变量时必须设置初始值
- const声明一个只读常量,这个常量不可改变
- let/const 声明的变量仅在块级作用域中有效。而 var 声明的变量在块级作用域外仍能访问到。
用var声明for循环变量:
用let声明for循环变量::
我们说 let 声明的变量仅在块级作用域内有效,变量i是let声明的,当前的 i 只在本轮循环有效,所以每一次循环的 i 其实都是一个新的变量。