原文链接: 快速介绍几个JS函数
JS中函数是一等公民,地位很高。本文介绍快速介绍三个函数:
throttle
节流函数debounce
去抖函数compose
组合函数,这函数就是把一系列函数按顺序一个个执行。
节流和去抖函数
当某些事件频繁触发造成不断执行DOM操作或资源加载等行为,这时你可能就会想到用节流和去抖函数来处理。
throttle
节流函数
节流函数就是预先设定一个执行周期,当调用动作的时刻大于等于执行周期则执行该动作,然后进入下一个新周期。
可以用在下面两个情景中:
- window对象的resize、scroll事件
- 拖拽时的mousemove事件
简单实现
functionthrottle (fn, delay) {
let last = 0
return(...args) => {
const now = Date.now()
if (now - last > delay) {
fn.call(this, args)
last = now
}
}
}
复制代码
debounce
去抖函数
去抖函数就是调用动作n毫秒后,才会执行该动作,若在这n毫秒内又调用此动作则将重新计算执行时间。
通常用在下面的场景中:
- 文字输入、自动完成的keyup事件
简单实现
functiondebounce (fn, delay) {
let last = 0
return(...args) => {
clearTimeout(last)
last = setTimeout(() => {
fn.call(this, args)
}, delay)
}
}
复制代码
这边找了一个网上的实现版本:
/*
* 频率控制 返回函数连续调用时,fn 执行频率限定为每多少时间执行一次
* @param fn {function} 需要调用的函数
* @param delay {number} 延迟时间,单位毫秒
* @param immediate {bool} 给 immediate参数传递false 绑定的函数先执行,而不是delay后后执行。
* @return {function}实际调用函数
*/var throttle = function (fn,delay, immediate, debounce) {
var curr = +newDate(),//当前事件
last_call = 0,
last_exec = 0,
timer = null,
diff, //时间差
context,//上下文
args,
exec = function () {
last_exec = curr;
fn.apply(context, args);
};
returnfunction () {
curr= +newDate();
context = this,
args = arguments,
diff = curr - (debounce ? last_call : last_exec) - delay;
clearTimeout(timer);
if (debounce) {
if (immediate) {
timer = setTimeout(exec, delay);
} elseif (diff >= 0) {
exec();
}
} else {
if (diff >= 0) {
exec();
} elseif (immediate) {
timer = setTimeout(exec, -diff);
}
}
last_call = curr;
}
};
/*
* 空闲控制 返回函数连续调用时,空闲时间必须大于或等于 delay,fn 才会执行
* @param fn {function} 要调用的函数
* @param delay {number} 空闲时间
* @param immediate {bool} 给 immediate参数传递false 绑定的函数先执行,而不是delay后后执行。
* @return {function}实际调用函数
*/var debounce = function (fn, delay, immediate) {
return throttle(fn, delay, immediate, true);
};
复制代码
自己画了一张图便于理解,最左边的boolean
值是上边的immediate
值,沿x轴的线是时间线,时间线上面是用户触发的动作,下面是函数的执行。
上面函数有点奇怪的地方就是immediate
参数传递false
绑定的函数先执行。 ![](data:image/svg+xml;utf8,<?xml version="1.0"?><svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="796" height="777"></svg>) 先看debounce
在immediate
不同的情况下的表现:
在immediate
为false
的情况下,第一次触发动作,函数就马上被执行了,后续的在delay时间段内重复按键都不会触发函数,而且会重置delay开始计算的时间点。当触发动作间隔时间超过delay后,又回到了初始状态,一触发动作就执行函数。
在immediate
为true
的情况下,触发动作后,函数并没有马上执行,只有在经过delay时间段内,没有触发动作时,函数才会被执行。
接着看throttle
在immediate
不同的情况下的表现:
在immediate
为false
的情况下,第一次触发动作,函数就马上被执行了,在这次执行后,在后续的delay时间段内触发动作都不会执行函数,间隔大于delay后,回到初始状态,触发动作函数就执行。
在immediate
为true
的情况下,第一次触发动作,函数就马上被执行了,同时定时器设置延时delay时间后在执行函数。其实和上面情况差不多,只不过会在delay后多执行一次。当然还有一些细节不同,图中可以看到,有两个执行之间时间并没有间隔delay。
compose
函数
这个直接上代码了,是从redux那边借过来的。
/**
* Composes single-argument functions from right to left. The rightmost
* function can take multiple arguments as it provides the signature for
* the resulting composite function.
*
* @param {...Function} funcs The functions to compose.
* @returns {Function} A function obtained by composing the argument functions
* from right to left. For example, compose(f, g, h) is identical to doing
* (...args) => f(g(h(...args))).
*/exportdefaultfunctioncompose(...funcs) {
if (funcs.length === 0) {
returnarg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
复制代码
核心代码就一行,没错,就一行。
没看到之前,我可能会通过for
循环来做,上面代码用到数组方法reduce
,在配合剩余参数语法和扩展运算符...
来传参就可以实现函数组合的功能,非常精简。
介绍到这里就结束了,后续碰到到惊艳的函数还会继续分享。