柯里化函数实现

一、概念

柯里化(Currying) 是将一个接受多个参数的函数转换为一系列接受单一参数的函数的技术。这样做的好处在于可以更灵活地处理函数参数,尤其是在函数式编程中。

二、科里化函数简单的实现

function currying(...initialArgs) {
	// 收集初始参数
	const args = [...initialArgs];
	// 内部函数用于收集后续参数
	const inner = (...newArgs) => {
		if (newArgs.length === 0) {
			// 如果没有新参数,则返回当前参数的总和
			return args.reduce((a, b) => a + b, 0);
		}
		args.push(...newArgs); // 收集新参数
		return inner; // 返回自身以支持链式调用
	};

	return inner; // 返回内部函数
}

代码实现步骤逻辑

  1. 这段代码实现了一个柯里化函数 currying,其主要功能是收集输入的参数并在最后返回这些参数的总和。
  2. currying 是一个接受任意数量初始参数的函数,使用了扩展运算符 (...initialArgs) 来收集这些参数。
  3. 在函数内部,创建一个数组 args,用于存储所有传入的参数。初始时,args 包含了 initialArgs 中的所有元素。
  4. 定义了一个内部函数 inner,这个函数也是使用了扩展运算符 (...newArgs) 以收集后续传入的参数。
  5. 当调用 inner 时,如果没有传入新的参数(即 newArgs.length === 0),则计算并返回当前 args 数组中所有参数的总和,使用 reduce 方法实现累加。
  6. 如果有新的参数传入,则将这些参数添加到 args 中,并返回 inner 本身,以支持链式调用。
  7. 最后,currying 函数返回 inner 函数,这样用户可以通过连续调用来传入多个参数。

三、科里化函数的应用场景

1. 创建带有默认参数的计算函数

// 假设我们需要一个计算函数,可以根据不同的运算符(如加法、减法、乘法、除法)进行计算。使用柯里化,我们可以方便地创建特定运算的计算器。
// 基础计算函数
function calculate(operator, a, b) {
	switch (operator) {
		case "add":
			return a + b;
		case "subtract":
			return a - b;
		case "multiply":
			return a * b;
		case "divide":
			return a / b;
		default:
			return null;
	}
}
// 柯里化函数
function curryingCalculate(operator) {
	return function (a) {
		return function (b) {
			return calculate(operator, a, b);
		};
	};
}
// 创建特定运算的计算器
const add = curryingCalculate("add");
const subtract = curryingCalculate("subtract");
// 使用示例
console.log(add(5)(3)); // 输出: 8
console.log(subtract(5)(3)); // 输出: 2

2. 事件处理器

// 在处理用户交互时,柯里化可以帮助我们创建更灵活的事件处理器。例如,创建一个带有默认参数的事件处理函数。
// 基础事件处理函数
function handleEvent(eventType, message) {
	console.log(`[${eventType}] ${message}`);
}
// 柯里化函数
function curryingHandleEvent(eventType) {
	return function (message) {
		handleEvent(eventType, message);
	};
}
// 创建特定事件处理器
const clickHandler = curryingHandleEvent("CLICK");
const hoverHandler = curryingHandleEvent("HOVER");
// 使用示例
clickHandler("Button clicked!"); // 输出: [CLICK] Button clicked!
hoverHandler("Element hovered!"); // 输出: [HOVER] Element hovered!

3. API 请求

// 在进行 API 请求时,柯里化可以帮助我们创建带有默认参数的请求函数,简化后续的请求调用。
// 基础 API 请求函数
function apiRequest(method, url, data) {
	console.log(`Method: ${method}, URL: ${url}, Data:`, data);
}

// 柯里化函数
function curryingApiRequest(method) {
	return function (url) {
		return function () {
			apiRequest(method, url, data);
		};
	};
}
// 创建特定方法的请求函数
const getRequest = curryingApiRequest("GET");
const postRequest = curryingApiRequest("POST");
// 使用示例
getRequest("/api/data")(); // 输出: Method: GET, URL: /api/data, Data: undefined
postRequest("/api/data")({ key: "value" }); // 输出: Method: POST, URL: /api/data, Data: { key: 'value' }

四、es-toolkit 库的实现

// 从 es-toolkit/compat 中导入 curry 以实现与 lodash 的完全兼容。
export function curry(func: (...args: any[]) => any): (...args: any[]) => any {
	if (func.length === 0 || func.length === 1) {
		return func;
	}
	return function (arg: any) {
		return makeCurry(func, func.length, [arg]);
	} as any;
}
function makeCurry<F extends (...args: any) => any>(
	origin: F,
	argsLength: number,
	args: any[]
) {
	if (args.length === argsLength) {
		return origin(...args);
	} else {
		const next = function (arg: Parameters<F>[0]) {
			return makeCurry(origin, argsLength, [...args, arg]);
		};
		return next as any;
	}
}

五、总结

通过以上三个例子,我们可以看到柯里化在实际开发中的优势:

  • 代码简洁:柯里化使得函数调用更加清晰和简洁。
  • 重用性:可以轻松创建不同的函数,避免重复代码。
  • 可维护性:修改逻辑时,只需在一个地方进行更改。
  • 灵活性:可以根据需要动态创建不同的功能,增强代码的灵活性。

这些特性使得柯里化在函数式编程和现代 JavaScript 开发中非常有用。

上次更新 2025/3/19 16:57:59