柯里化
(颗粒化)
作用:参数复用、延迟执行、函数组合
function uri_curring(protocol) {
return function (hostname, pathname) {
return `${protocol}://${hostname}/${pathname}`
}
}
// 生成一个https的uri,可用于多次调用
const uri_https = uri_curring('https');
const uri1 = uri_https('www.baidu1.com', 'index1.html');
const uri2 = uri_https('www.baidu2.com', 'index2.html');
console.log(uri1); // https://www.baidu1.com/index1.html
console.log(uri2); // https://www.baidu2.com/index2.html
/**
* 实现柯里化函数
* @param {Function} fn 要柯里化的函数
* @param {...any} args 初始参数
* @returns {Function} 柯里化后的函数
*/
function curry(fn, ...args) {
// 获取函数参数个数
let len = fn.length;
// 如果传入的参数数量大于或等于函数参数个数,则直接调用函数
if (args.length >= len) return fn(...args);
// 否则返回一个新函数,继续接受新的参数
return function (...newArgs) {
// 合并之前的参数和新参数
let _args = args.concat(newArgs);
// 递归调用 curry 函数
return curry.call(this, fn, ..._args);
}
}
节流防抖
节流
触发高频事件,但在n秒内只会执行一次,在于稀释函数的执行频率,侧重于一段时间内只执行一次
(就像游戏里无论手速多快,多次平A也有频率上限)
应用场景:
- window对象的resize、scroll事件
- 拖拽事件的mousemove
- 射击游戏中的mousedown、keydown事件
- 文字输入、自动完成的keyup事件
防抖
触发高频事件后,n秒内只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间,侧重于一段时间内多次触发只在最后执行一次
(就像游戏里释放技能的时候,再按一次技能就会重新冷却)
应用场景:
- 提交按钮、用户注册时候的手机号验证、邮箱验证
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
height: 4000px;
background-color: #000;
}
</style>
</head>
<body>
<input id="input"></input>
<div id="div"></div>
<script>
function sendRequest() {
console.log("发送请求");
}
// 节流:
// document.getElementById("div").onscroll = throttle(sendRequest, 1000)
const onscroll = throttle(sendRequest, 1000)
function throttle(fn, delayTime) {
let valve = true;
return function () {
if (!valve) {
return;
}
valve = false;
setTimeout(() => {
fn && fn()
valve = true;
}, delayTime)
}
}
// 防抖:输入完成后间隔一秒再发送请求
document.getElementById("input").oninput = antiShake(sendRequest, 1000);
function antiShake(fn, delayTime) {
let timer = null;
return function () {
if (timer) {
clearTimeout(timer)
};
timer = setTimeout(() => {
fn && fn();
}, delayTime)
};
}
</script>
</body>
</html>
手写节流
function throttle(callback, delayTime, leading = false, trailing = true) {
let state = true;
let timer = null;
// 参数类型检查
if (typeof callback !== 'function' || typeof delayTime !== 'number' || typeof leading !== 'boolean' || typeof trailing !== 'boolean') {
console.error('throttle() 传入参数类型错误');
return;
};
// 使用...args保留所有参数
return function (...args) {
// 立即执行
if (leading && state) {
state = false;
setTimeout(() => {
// 使用apply()保留this指向
callback && callback.apply(this, args);
state = true;
}, delayTime)
}
// 延迟执行
if (!timer) {
timer = setTimeout(() => {
if (trailing) callback && callback.apply(this, args);
state = true;
timer = null;
}, delayTime)
}
}
};
手写防抖
function debounce(callback, delayTime, immediate = false) {
if (typeof callback !== 'function' || typeof delayTime !== 'number') {
console.error('debounce() 传入参数类型错误');
return;
}
let timer = null;
// 返回一个函数,用于取消防抖
const debounced = function (...args) {
if (immediate && !timer) {
// 立即执行
callback.apply(this, args);
}
clearTimeout(timer);
timer = setTimeout(() => {
callback.apply(this, args);
timer = null;
}, delayTime);
};
// 取消防抖
debounced.cancel = function () {
clearTimeout(timer);
timer = null;
};
return debounced;
};