1、实现curry
科里化(Currying) 是将一个接受多个参数的函数转换成一系列接受单一参数的函数的技术。换句话说,科里化将一个函数的多个参数“拆解”成多个函数,每个函数只接受一个参数,并且每个函数都返回一个接受下一个参数的函数,直到所有参数都被接收并返回最终结果。
function curry(fn, ...args1) {
let argList = [...args1];
// 返回一个新的函数
return function (...args) {
// 将当前传入的参数添加到参数列表中
argList = [...argList, ...args];
// 如果参数数量已经足够,则计算并返回结果
if (argList.length >= fn.length) {
return fn(...argList); // 调用原始函数并传入所有参数
} else {
// 否则,返回一个新的函数,继续等待传入参数
return curry(fn, ...argList);
}
};
}
// 示例:一个需要两个参数的函数
function add(a, b) {
return a + b;
}
const curriedAdd = curry(add);
console.log(curriedAdd(2)(3)); // 输出 5
2、实现支持placeholder的curry()
本题的核心
-
参数收集逻辑:
-
每次调用都会检查是否收集了足够的非占位符参数
-
如果足够,调用原函数
-
如果不够,返回一个新函数继续收集
-
-
占位符替换:
-
在组合参数时,用实际参数按顺序替换占位符
-
如果实际参数不足,保留占位符等待下次调用
-
const _ = Symbol("placehold")
function curry(fn) {
return function curried(...args) {
// 检查是否收集了足够的非占位符参数
const sufficientArgs = args.length >= fn.length &&
args.slice(0, fn.length).every(arg => arg !== _);
// 1、判断是否是收集够了参数, 如果参数够了就掉用函数
if (sufficientArgs) {
return fn.apply(this, args.slice(0, fn.length));
}
// 2、否则,将函数按照传入顺序排序
return function (...nextArgs) {
let combins = [];
let nextArgsIndex = 0
args.forEach(item => {
if (item === _ && nextArgsIndex < nextArgs.length) {
combins.push(nextArgs[nextArgsIndex])
nextArgsIndex++
} else if (item !== _) {
combins.push(item)
} else {
combins.push(_)
}
})
if (nextArgsIndex < nextArgs.length) {
combins = combins.concat(nextArgs.slice(nextArgsIndex))
}
return curried.apply(this, combins)
}
}
}
3、实现Array.prototype.flat() 函数
重点:
1、了解flat参数,deepth是铺平几层
function _flat(arrList, deepth) {
if (!Array.isArray(arrList) || !arrList.length) return [];
if (deepth === 0) return arrList;
let arr = []
arrList.forEach(item => {
if (Array.isArray(item)) {
arr = arr.concat(_flat(item, deepth - 1))
} else {
arr.push(item)
}
})
return arr
}
4、手写throttle()
节流概念:
用于控制函数在一定时间间隔内只执行一次。
可以用到节流技术的操作:
1、滚动
2、鼠标移动
3、窗口大小改变
let timed = null
function throttle(fn, delay) {
return function () {
if (!timed) {
timed = setTimeout(() => {
fn();
clearTimeout(timed);
}, delay);
}
}
}
5、手写debounce()
防抖概念:
当连续触发事件时,只有在事件停止触发一段时间后,才会执行处理函数
防抖应用场景:
1、搜索框
2、窗口大小调整
3、表单验证
let timed = null
function debounce(fn, delay) {
return function () {
if (timed) {
clearTimeout(timed);
}
timed = setTimeout(() => {
fn();
timed = null;
}, delay);
}
}