Search K
Appearance
Appearance
📊 SEO元描述:2024年最新JavaScript函数式编程教程,详解纯函数概念、函数组合技巧、柯里化实现方法。包含完整代码示例和实际应用,适合前端开发者掌握JavaScript函数式编程核心概念。
核心关键词:JavaScript函数式编程2024、纯函数、函数组合、柯里化、JavaScript函数式编程基础
长尾关键词:JavaScript纯函数是什么、函数组合怎么实现、JavaScript柯里化有什么用、函数式编程优势
通过本节JavaScript函数式编程基础,你将系统性掌握:
纯函数是什么?这是给定相同输入总是返回相同输出,且没有副作用的函数。纯函数是函数式编程的基石,具有可预测性、可测试性和可缓存性等重要特征。
💡 学习建议:理解纯函数是掌握函数式编程的关键,要重点关注副作用的识别和避免
纯函数必须满足两个核心条件:
// 🎉 纯函数 vs 非纯函数对比
console.log('=== 纯函数示例 ===');
// ✅ 纯函数:数学运算
function add(a, b) {
return a + b;
}
function multiply(x, y) {
return x * y;
}
function square(n) {
return n * n;
}
// 测试纯函数的确定性
console.log('add(2, 3):', add(2, 3)); // 总是返回5
console.log('add(2, 3):', add(2, 3)); // 总是返回5
console.log('multiply(4, 5):', multiply(4, 5)); // 总是返回20
// ✅ 纯函数:字符串处理
function toUpperCase(str) {
return str.toUpperCase();
}
function getLength(str) {
return str.length;
}
function concatenate(str1, str2) {
return str1 + str2;
}
console.log('toUpperCase("hello"):', toUpperCase("hello")); // 总是返回"HELLO"
// ✅ 纯函数:数组处理(不修改原数组)
function doubleArray(arr) {
return arr.map(x => x * 2);
}
function filterEven(arr) {
return arr.filter(x => x % 2 === 0);
}
function sumArray(arr) {
return arr.reduce((sum, x) => sum + x, 0);
}
const numbers = [1, 2, 3, 4, 5];
console.log('原数组:', numbers);
console.log('doubleArray:', doubleArray(numbers));
console.log('原数组未变:', numbers); // 原数组保持不变
console.log('=== 非纯函数示例 ===');
// ❌ 非纯函数:依赖外部状态
let globalCounter = 0;
function impureIncrement() {
globalCounter++; // 修改外部状态
return globalCounter;
}
console.log('impureIncrement():', impureIncrement()); // 1
console.log('impureIncrement():', impureIncrement()); // 2 - 相同调用,不同结果
// ❌ 非纯函数:产生副作用
function impureLog(message) {
console.log(message); // 副作用:输出到控制台
return message;
}
// ❌ 非纯函数:修改输入参数
function impureSort(arr) {
return arr.sort(); // 修改原数组
}
const testArray = [3, 1, 4, 1, 5];
console.log('排序前:', testArray);
const sorted = impureSort(testArray);
console.log('排序后:', sorted);
console.log('原数组被修改:', testArray); // 原数组被修改了
// ✅ 纯函数版本:不修改输入
function pureSort(arr) {
return [...arr].sort(); // 创建副本再排序
}
const testArray2 = [3, 1, 4, 1, 5];
console.log('纯函数排序前:', testArray2);
const pureSorted = pureSort(testArray2);
console.log('纯函数排序后:', pureSorted);
console.log('原数组未变:', testArray2); // 原数组保持不变
// ❌ 非纯函数:依赖随机数或时间
function impureRandom() {
return Math.random(); // 每次调用结果不同
}
function impureTimestamp() {
return Date.now(); // 每次调用结果不同
}
// ✅ 纯函数:将不确定因素作为参数
function pureRandomProcessor(randomValue, data) {
return data.map(x => x * randomValue);
}
function pureTimeFormatter(timestamp, format) {
const date = new Date(timestamp);
return format === 'short' ? date.toDateString() : date.toISOString();
}
console.log('纯函数处理随机值:', pureRandomProcessor(0.5, [1, 2, 3, 4]));
console.log('纯函数格式化时间:', pureTimeFormatter(Date.now(), 'short'));// 🎉 纯函数的实际应用场景
console.log('=== 数据转换和处理 ===');
// 用户数据处理
const users = [
{ id: 1, name: 'Alice', age: 25, active: true },
{ id: 2, name: 'Bob', age: 30, active: false },
{ id: 3, name: 'Charlie', age: 35, active: true }
];
// ✅ 纯函数:数据转换
function formatUser(user) {
return {
id: user.id,
displayName: user.name.toUpperCase(),
ageGroup: user.age < 30 ? 'young' : 'mature',
status: user.active ? 'active' : 'inactive'
};
}
function calculateUserStats(users) {
return {
total: users.length,
active: users.filter(u => u.active).length,
averageAge: users.reduce((sum, u) => sum + u.age, 0) / users.length
};
}
const formattedUsers = users.map(formatUser);
const userStats = calculateUserStats(users);
console.log('格式化用户:', formattedUsers);
console.log('用户统计:', userStats);
console.log('=== 业务逻辑处理 ===');
// 订单处理系统
function calculateOrderTotal(items) {
return items.reduce((total, item) => total + (item.price * item.quantity), 0);
}
function applyDiscount(total, discountPercent) {
return total * (1 - discountPercent / 100);
}
function calculateTax(amount, taxRate) {
return amount * taxRate;
}
function processOrder(items, discountPercent = 0, taxRate = 0.1) {
const subtotal = calculateOrderTotal(items);
const discountedTotal = applyDiscount(subtotal, discountPercent);
const tax = calculateTax(discountedTotal, taxRate);
const finalTotal = discountedTotal + tax;
return {
subtotal,
discount: subtotal - discountedTotal,
tax,
total: finalTotal
};
}
const orderItems = [
{ name: 'Laptop', price: 999, quantity: 1 },
{ name: 'Mouse', price: 25, quantity: 2 }
];
const orderResult = processOrder(orderItems, 10, 0.08);
console.log('订单处理结果:', orderResult);
console.log('=== 配置和验证 ===');
// 表单验证
function validateEmail(email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
function validatePassword(password) {
return password.length >= 8 && /[A-Z]/.test(password) && /[0-9]/.test(password);
}
function validateAge(age) {
return typeof age === 'number' && age >= 18 && age <= 120;
}
function validateUser(userData) {
const errors = [];
if (!validateEmail(userData.email)) {
errors.push('Invalid email format');
}
if (!validatePassword(userData.password)) {
errors.push('Password must be at least 8 characters with uppercase and number');
}
if (!validateAge(userData.age)) {
errors.push('Age must be between 18 and 120');
}
return {
isValid: errors.length === 0,
errors
};
}
const userData1 = { email: 'user@example.com', password: 'Password123', age: 25 };
const userData2 = { email: 'invalid-email', password: '123', age: 15 };
console.log('有效用户验证:', validateUser(userData1));
console.log('无效用户验证:', validateUser(userData2));
console.log('=== 纯函数的可缓存性 ===');
// 缓存装饰器
function memoize(fn) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
console.log('从缓存返回:', key);
return cache.get(key);
}
console.log('计算结果:', key);
const result = fn(...args);
cache.set(key, result);
return result;
};
}
// 昂贵的纯函数计算
function expensiveCalculation(n) {
let result = 0;
for (let i = 0; i < n * 1000000; i++) {
result += Math.sqrt(i);
}
return result;
}
const memoizedCalculation = memoize(expensiveCalculation);
console.time('第一次计算');
console.log('结果1:', memoizedCalculation(100));
console.timeEnd('第一次计算');
console.time('第二次计算(缓存)');
console.log('结果2:', memoizedCalculation(100));
console.timeEnd('第二次计算(缓存)');**函数组合是什么?**这是将多个简单函数组合成复杂函数的技术。函数组合允许我们通过组合小的、可重用的函数来构建复杂的数据处理管道。
// 🎉 函数组合的实现方法
console.log('=== 基本函数组合 ===');
// 基础函数
const add = (x) => (y) => x + y;
const multiply = (x) => (y) => x * y;
const subtract = (x) => (y) => y - x;
// 手动组合
function manualCompose(x) {
return multiply(2)(add(3)(x)); // ((x + 3) * 2)
}
console.log('手动组合 manualCompose(5):', manualCompose(5)); // (5 + 3) * 2 = 16
// compose函数:从右到左组合
function compose(...functions) {
return function(value) {
return functions.reduceRight((acc, fn) => fn(acc), value);
};
}
// pipe函数:从左到右组合
function pipe(...functions) {
return function(value) {
return functions.reduce((acc, fn) => fn(acc), value);
};
}
// 使用compose(从右到左)
const composedFunction = compose(
multiply(2), // 最后执行
add(3) // 先执行
);
console.log('compose组合 composedFunction(5):', composedFunction(5)); // (5 + 3) * 2 = 16
// 使用pipe(从左到右,更直观)
const pipedFunction = pipe(
add(3), // 先执行
multiply(2) // 后执行
);
console.log('pipe组合 pipedFunction(5):', pipedFunction(5)); // (5 + 3) * 2 = 16
console.log('=== 复杂函数组合 ===');
// 字符串处理函数
const trim = (str) => str.trim();
const toLowerCase = (str) => str.toLowerCase();
const removeSpaces = (str) => str.replace(/\s+/g, '');
const addPrefix = (prefix) => (str) => prefix + str;
const addSuffix = (suffix) => (str) => str + suffix;
// 组合字符串处理管道
const processString = pipe(
trim,
toLowerCase,
removeSpaces,
addPrefix('processed_'),
addSuffix('_done')
);
const testString = ' Hello World ';
console.log('原字符串:', `"${testString}"`);
console.log('处理后:', processString(testString)); // "processed_helloworld_done"
console.log('=== 数据处理管道 ===');
// 数据处理函数
const filterActive = (users) => users.filter(user => user.active);
const sortByAge = (users) => [...users].sort((a, b) => a.age - b.age);
const mapToNames = (users) => users.map(user => user.name);
const joinWithComma = (names) => names.join(', ');
// 组合数据处理管道
const processUsers = pipe(
filterActive,
sortByAge,
mapToNames,
joinWithComma
);
const usersData = [
{ name: 'Alice', age: 30, active: true },
{ name: 'Bob', age: 25, active: false },
{ name: 'Charlie', age: 35, active: true },
{ name: 'Diana', age: 28, active: true }
];
console.log('用户处理结果:', processUsers(usersData)); // "Bob, Diana, Alice, Charlie"
console.log('=== 异步函数组合 ===');
// 异步函数组合
function composeAsync(...functions) {
return function(value) {
return functions.reduceRight(async (acc, fn) => {
const resolvedAcc = await acc;
return fn(resolvedAcc);
}, Promise.resolve(value));
};
}
function pipeAsync(...functions) {
return function(value) {
return functions.reduce(async (acc, fn) => {
const resolvedAcc = await acc;
return fn(resolvedAcc);
}, Promise.resolve(value));
};
}
// 异步处理函数
const fetchUserData = async (userId) => {
// 模拟API调用
await new Promise(resolve => setTimeout(resolve, 100));
return { id: userId, name: `User${userId}`, email: `user${userId}@example.com` };
};
const validateUserData = async (userData) => {
await new Promise(resolve => setTimeout(resolve, 50));
return { ...userData, isValid: userData.email.includes('@') };
};
const saveUserData = async (userData) => {
await new Promise(resolve => setTimeout(resolve, 75));
return { ...userData, saved: true, timestamp: Date.now() };
};
// 异步管道
const processUserAsync = pipeAsync(
fetchUserData,
validateUserData,
saveUserData
);
// 使用异步组合
async function testAsyncComposition() {
try {
const result = await processUserAsync(123);
console.log('异步处理结果:', result);
} catch (error) {
console.error('异步处理错误:', error);
}
}
// testAsyncComposition();
console.log('=== 条件组合 ===');
// 条件组合函数
function when(predicate, fn) {
return function(value) {
return predicate(value) ? fn(value) : value;
};
}
function unless(predicate, fn) {
return function(value) {
return predicate(value) ? value : fn(value);
};
}
// 条件处理
const isEven = (n) => n % 2 === 0;
const double = (n) => n * 2;
const triple = (n) => n * 3;
const conditionalProcess = pipe(
when(isEven, double), // 如果是偶数则翻倍
unless(isEven, triple) // 如果不是偶数则三倍
);
console.log('条件处理 conditionalProcess(4):', conditionalProcess(4)); // 8 (偶数翻倍)
console.log('条件处理 conditionalProcess(5):', conditionalProcess(5)); // 15 (奇数三倍)// 🎉 函数组合的实际应用
console.log('=== 表单数据处理 ===');
// 表单处理管道
const parseFormData = (formData) => {
const parsed = {};
for (const [key, value] of formData.entries()) {
parsed[key] = value;
}
return parsed;
};
const validateFormData = (data) => {
const errors = [];
if (!data.name || data.name.length < 2) errors.push('Name too short');
if (!data.email || !data.email.includes('@')) errors.push('Invalid email');
if (!data.age || data.age < 18) errors.push('Must be 18 or older');
return { ...data, errors, isValid: errors.length === 0 };
};
const sanitizeFormData = (data) => ({
...data,
name: data.name?.trim(),
email: data.email?.toLowerCase().trim(),
age: parseInt(data.age) || 0
});
const processFormData = pipe(
parseFormData,
sanitizeFormData,
validateFormData
);
// 模拟表单数据
const mockFormData = new FormData();
mockFormData.append('name', ' Alice ');
mockFormData.append('email', ' ALICE@EXAMPLE.COM ');
mockFormData.append('age', '25');
console.log('表单处理结果:', processFormData(mockFormData));
console.log('=== API响应处理 ===');
// API响应处理管道
const extractData = (response) => response.data;
const filterValidItems = (items) => items.filter(item => item.status === 'active');
const transformItems = (items) => items.map(item => ({
id: item.id,
title: item.name.toUpperCase(),
description: item.description || 'No description',
createdAt: new Date(item.created_at).toLocaleDateString()
}));
const sortByTitle = (items) => [...items].sort((a, b) => a.title.localeCompare(b.title));
const processApiResponse = pipe(
extractData,
filterValidItems,
transformItems,
sortByTitle
);
// 模拟API响应
const mockApiResponse = {
data: [
{ id: 1, name: 'zebra', description: 'A zebra', status: 'active', created_at: '2024-01-01' },
{ id: 2, name: 'apple', description: 'An apple', status: 'inactive', created_at: '2024-01-02' },
{ id: 3, name: 'banana', status: 'active', created_at: '2024-01-03' }
]
};
console.log('API响应处理结果:', processApiResponse(mockApiResponse));
console.log('=== 数据分析管道 ===');
// 销售数据分析
const groupByProduct = (sales) => {
return sales.reduce((groups, sale) => {
if (!groups[sale.product]) groups[sale.product] = [];
groups[sale.product].push(sale);
return groups;
}, {});
};
const calculateProductTotals = (groupedSales) => {
const totals = {};
for (const [product, sales] of Object.entries(groupedSales)) {
totals[product] = {
totalRevenue: sales.reduce((sum, sale) => sum + sale.amount, 0),
totalQuantity: sales.reduce((sum, sale) => sum + sale.quantity, 0),
averagePrice: sales.reduce((sum, sale) => sum + sale.amount, 0) / sales.length
};
}
return totals;
};
const findTopProducts = (productTotals) => {
return Object.entries(productTotals)
.sort(([,a], [,b]) => b.totalRevenue - a.totalRevenue)
.slice(0, 3)
.map(([product, data]) => ({ product, ...data }));
};
const analyzeSalesData = pipe(
groupByProduct,
calculateProductTotals,
findTopProducts
);
const salesData = [
{ product: 'Laptop', amount: 999, quantity: 1 },
{ product: 'Mouse', amount: 25, quantity: 3 },
{ product: 'Laptop', amount: 999, quantity: 2 },
{ product: 'Keyboard', amount: 75, quantity: 1 },
{ product: 'Mouse', amount: 25, quantity: 1 }
];
console.log('销售数据分析结果:', analyzeSalesData(salesData));**柯里化是什么?**这是将接受多个参数的函数转换为一系列接受单个参数的函数的技术。柯里化提供了更灵活的函数调用方式和更好的函数复用性。
// 🎉 柯里化的实现和应用
console.log('=== 柯里化基本概念 ===');
// 普通函数
function normalAdd(a, b, c) {
return a + b + c;
}
// 手动柯里化
function curriedAdd(a) {
return function(b) {
return function(c) {
return a + b + c;
};
};
}
// 箭头函数版本
const arrowCurriedAdd = a => b => c => a + b + c;
console.log('普通函数:', normalAdd(1, 2, 3)); // 6
console.log('柯里化函数:', curriedAdd(1)(2)(3)); // 6
console.log('箭头柯里化:', arrowCurriedAdd(1)(2)(3)); // 6
// 通用柯里化函数
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return function(...nextArgs) {
return curried.apply(this, args.concat(nextArgs));
};
}
};
}
// 使用通用柯里化
const curriedMultiply = curry((a, b, c, d) => a * b * c * d);
console.log('通用柯里化测试:');
console.log(curriedMultiply(2)(3)(4)(5)); // 120
console.log(curriedMultiply(2, 3)(4, 5)); // 120
console.log(curriedMultiply(2)(3, 4, 5)); // 120
console.log('=== 柯里化的实际应用 ===');
// 配置函数
const createLogger = curry((level, prefix, message) => {
const timestamp = new Date().toISOString();
console.log(`[${timestamp}] [${level}] ${prefix}: ${message}`);
});
// 创建专用日志函数
const debugLogger = createLogger('DEBUG');
const errorLogger = createLogger('ERROR');
const apiLogger = debugLogger('API');
const dbLogger = errorLogger('DATABASE');
apiLogger('用户请求数据');
dbLogger('连接失败');
// 数据处理
const processData = curry((transformer, filter, data) => {
return data.filter(filter).map(transformer);
});
// 创建专用处理函数
const processActiveUsers = processData(
user => ({ ...user, displayName: user.name.toUpperCase() })
)(user => user.active);
const processHighEarners = processData(
user => ({ ...user, salaryLevel: user.salary > 70000 ? 'high' : 'normal' })
)(user => user.salary > 50000);
const userData = [
{ name: 'Alice', salary: 75000, active: true },
{ name: 'Bob', salary: 45000, active: false },
{ name: 'Charlie', salary: 85000, active: true }
];
console.log('活跃用户处理:', processActiveUsers(userData));
console.log('高收入用户处理:', processHighEarners(userData));
console.log('=== 柯里化与函数组合 ===');
// 柯里化的数学函数
const add = curry((a, b) => a + b);
const multiply = curry((a, b) => a * b);
const divide = curry((a, b) => a / b);
const subtract = curry((a, b) => a - b);
// 创建专用函数
const addTen = add(10);
const multiplyByTwo = multiply(2);
const divideByFive = divide(5);
// 组合使用
const complexCalculation = pipe(
addTen, // +10
multiplyByTwo, // *2
divideByFive // /5
);
console.log('复杂计算 complexCalculation(5):', complexCalculation(5)); // ((5+10)*2)/5 = 6
// 数组处理的柯里化
const map = curry((fn, arr) => arr.map(fn));
const filter = curry((predicate, arr) => arr.filter(predicate));
const reduce = curry((reducer, initial, arr) => arr.reduce(reducer, initial));
// 创建专用数组处理函数
const doubleAll = map(x => x * 2);
const filterEven = filter(x => x % 2 === 0);
const sumAll = reduce((sum, x) => sum + x, 0);
const numbers = [1, 2, 3, 4, 5, 6];
console.log('原数组:', numbers);
console.log('全部翻倍:', doubleAll(numbers));
console.log('过滤偶数:', filterEven(numbers));
console.log('求和:', sumAll(numbers));
// 组合数组处理
const processNumbers = pipe(
doubleAll,
filterEven,
sumAll
);
console.log('组合处理结果:', processNumbers(numbers)); // [2,4,6,8,10,12] -> 42
console.log('=== 柯里化的高级应用 ===');
// 验证器工厂
const createValidator = curry((rule, errorMessage, value) => {
return rule(value) ? { valid: true } : { valid: false, error: errorMessage };
});
// 创建具体验证器
const validateRequired = createValidator(
value => value != null && value !== '',
'This field is required'
);
const validateMinLength = curry((minLength, value) =>
createValidator(
val => val && val.length >= minLength,
`Minimum length is ${minLength}`
)(value)
);
const validateEmail = createValidator(
value => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value),
'Invalid email format'
);
// 组合验证器
function validateField(value, ...validators) {
for (const validator of validators) {
const result = validator(value);
if (!result.valid) {
return result;
}
}
return { valid: true };
}
// 测试验证
console.log('验证空值:', validateField('', validateRequired));
console.log('验证短密码:', validateField('123', validateMinLength(8)));
console.log('验证邮箱:', validateField('user@example.com', validateRequired, validateEmail));
// HTTP请求构建器
const createRequest = curry((method, baseUrl, endpoint, options) => {
return {
method,
url: `${baseUrl}${endpoint}`,
...options
};
});
// 创建API客户端
const apiRequest = createRequest('GET', 'https://api.example.com');
const postRequest = createRequest('POST', 'https://api.example.com');
const getUsers = apiRequest('/users');
const createUser = postRequest('/users');
console.log('GET请求配置:', getUsers({}));
console.log('POST请求配置:', createUser({
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'John' })
}));通过本节JavaScript函数式编程基础的学习,你已经掌握:
"函数式编程不仅是一种编程范式,更是一种思维方式。掌握它将让你的代码更加优雅、可维护和可测试!"