详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用

简介: 柯里化是一种强大的函数式编程技术,它通过将函数分解为单参数形式,实现了灵活性与可复用性的统一。无论是参数复用、延迟执行,还是函数组合,柯里化都为现代编程提供了极大的便利。 从 Redux 的选择器优化到复杂的数据流处理,再到深度嵌套的函数优化,柯里化在实际开发中展现出了非凡的价值。如果你希望编写更简洁、更优雅的代码,柯里化无疑是一个值得深入学习和实践的工具。从简单的实现到复杂的应用,希望这篇博客能为你揭开柯里化的奥秘,助力你的开发之旅! 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一


作者:watermelo37

涉及领域:Vue、SpingBoot、Docker、LLM、python等

---------------------------------------------------------------------

温柔地对待温柔的人,包容的三观就是最大的温柔。

---------------------------------------------------------------------

image.gif 编辑

详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用

       柯里化(Currying)是函数式编程中的一颗璀璨明珠,它不仅提升了代码的灵活性与可重用性,还提供了一种全新的函数设计思路。本篇博客将带你深入了解柯里化,从概念到实际应用,从简单实现到底层机制,全面解析这一强大的编程技术。

image.gif 编辑

一、什么是柯里化?

1、原理解析

       柯里化是将一个接受多个参数的函数转换为一系列单参数函数的过程。换句话说,柯里化后的函数会逐步接收参数,每次只接收一个或部分参数,直到收集到足够的参数时才真正执行。

       柯里化的概念源于逻辑学家哈斯凯尔·柯里(Haskell Curry),他的研究为函数式编程奠定了理论基础。如今,柯里化已成为现代编程语言中的重要组成部分,尤其在函数式编程语言(如 Haskell、Scala)和 JavaScript 等动态语言中广泛应用。

2、一个直观的例子

       假设我们有一个普通的求和函数:

function sum(a, b, c) {
  return a + b + c;
}

image.gif

       使用柯里化后,我们可以这样调用:

const curriedSum = curry(sum);
const result = curriedSum(1)(2)(3); // 6

image.gif

       甚至可以分步调用:

const partialSum = curriedSum(1); // 固定第一个参数
const result = partialSum(2)(3); // 6

image.gif

       这种灵活的调用方式得益于柯里化的设计。

       curry(柯里化的核心函数)是一种用于将多参数函数转化为逐步接收参数的函数的工具。在 JavaScript 中,curry 函数通常实现为一个高阶函数,它接收一个原始函数作为参数,并返回一个新的函数,可以逐个或分批接收原始函数的参数。

二、如何实现柯里化?

1、底层实现

       让我们从零实现一个通用的 curry 函数。

function curry(fn) {
  return function curried(...args) {
    if (args.length >= fn.length) {
      return fn.apply(this, args);
    } else {
      return function(...args2) {
        return curried.apply(this, args.concat(args2));
      };
    }
  };
}

image.gif

2、工作原理解析

  1. 初次调用:外层 curry 函数接受一个目标函数 fn。
  2. 参数累积:curried 函数检测当前参数数量是否满足 fn 的参数要求(fn.length)。
  3. 递归调用:如果未满足,则返回一个新函数,继续接收剩余参数。
  4. 执行原函数:当参数数量足够时,调用 fn 并返回结果。

3、测试我们的实现

function multiply(a, b, c) {
  return a * b * c;
}
function curry(fn) {
  return function curried(...args) {
    if (args.length >= fn.length) {
      return fn.apply(this, args);
    } else {
      return function(...args2) {
        return curried.apply(this, args.concat(args2));
      };
    }
  };
}
const curriedMultiply = curry(multiply);
console.log(curriedMultiply(2)(3)(4)); // 24
console.log(curriedMultiply(2, 3)(4)); // 24
console.log(curriedMultiply(2)(3, 4)); // 24

image.gif

三、柯里化的优点

1. 参数复用

       通过固定部分参数,柯里化使函数调用更加灵活。例如:

function greet(greeting, name) {
  return `${greeting}, ${name}!`;
}
const sayHello = curry(greet)("Hello");
console.log(sayHello("Alice")); // Hello, Alice!
console.log(sayHello("Bob"));   // Hello, Bob!

image.gif

2. 延迟执行

       柯里化允许延迟计算,直到所有参数准备就绪。

const add = curry((a, b) => a + b);
const addFive = add(5);
console.log(addFive(10)); // 15

image.gif

3. 函数组合

       柯里化与函数组合结合使用时,能够提升代码的可读性和模块化程度。例如:

const compose = (f, g) => (x) => f(g(x));
const addOne = (x) => x + 1;
const double = (x) => x * 2;
const addOneThenDouble = compose(double, addOne);
console.log(addOneThenDouble(3)); // 8

image.gif

       通过柯里化,我们可以轻松定义和组合类似的函数。

四、为什么柯里化如此强大?

       柯里化的核心在于其函数设计理念,它将复杂的操作分解为简单的步骤,每个步骤只关注一个变量。这种设计符合数学中 "单一变量函数" 的思想,使代码更加纯粹、可测试和易于推导。

       此外,柯里化为函数式编程的核心特性 "无副作用" 提供了有力支持。柯里化函数通常不会修改全局状态,而是通过参数传递上下文,使代码更加健壮。

五、实际应用场景

1. 高阶函数:Redux Selector 的场景模拟

       在 Redux 的 reselect  库中,柯里化用于创建高性能的 memoized 选择器:

假设我们管理一个电商网站,用户的购物车和订单状态保存在 Redux 状态树中:

const selectCart = (state) => state.cart;
const selectCartItems = createSelector(
  selectCart,
  (cart) => cart.items
);
const selectCartTotal = createSelector(
  selectCartItems,
  (items) => items.reduce((total, item) => total + item.price * item.quantity, 0)
);
const cartTotal = selectCartTotal(state);
console.log(`Cart Total: $${cartTotal}`);

image.gif

       在这个例子中,柯里化使得创建高性能的派生数据函数变得轻而易举,避免了重复计算。

2. 数据管道:构建复杂的数据流

       在实际场景中,柯里化可以用于构建复杂的数据流处理。

       例如,一个社交媒体平台需要处理一系列数据操作,包括过滤敏感词、格式化文本、统计字数等:

const filterSensitiveWords = curry((words, text) => 
  words.reduce((acc, word) => acc.replace(new RegExp(word, 'gi'), '***'), text)
);
const formatText = (text) => text.trim().toLowerCase();
const countWords = (text) => text.split(/\s+/).length;
const processTextPipeline = compose(
  countWords,
  formatText,
  filterSensitiveWords(['badword', 'offensive'])
);
const result = processTextPipeline(" This is a BadWord example! Badword is offensive. ");
console.log(result); // 输出处理后的字数

image.gif

       这种数据管道式的构建方式,结合柯里化和函数组合,极大提升了代码的可读性和维护性。

3. 深度嵌套函数的优化

       柯里化还能简化深度嵌套的调用,避免回调地狱。例如,假设我们要处理一系列 API 数据请求:

const fetchWithAuth = curry((authToken, endpoint) => 
  fetch(endpoint, { headers: { Authorization: `Bearer ${authToken}` } })
);
const fetchUserData = fetchWithAuth('my-secure-token');
Promise.all([
  fetchUserData('/api/user/1'),
  fetchUserData('/api/user/2')
])
  .then(([user1, user2]) => Promise.all([user1.json(), user2.json()]))
  .then(console.log)
  .catch(console.error);

image.gif

       通过柯里化,我们可以轻松创建基于上下文的高阶函数,避免了大量重复代码。

六、总结

       柯里化是一种强大的函数式编程技术,它通过将函数分解为单参数形式,实现了灵活性与可复用性的统一。无论是参数复用、延迟执行,还是函数组合,柯里化都为现代编程提供了极大的便利。

       从 Redux 的选择器优化到复杂的数据流处理,再到深度嵌套的函数优化,柯里化在实际开发中展现出了非凡的价值。如果你希望编写更简洁、更优雅的代码,柯里化无疑是一个值得深入学习和实践的工具。从简单的实现到复杂的应用,希望这篇博客能为你揭开柯里化的奥秘,助力你的开发之旅!

       只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~

       其他热门文章,请关注:

       极致的灵活度满足工程美学:用Vue Flow绘制一个完美流程图

       你真的会使用Vue3的onMounted钩子函数吗?Vue3中onMounted的用法详解

       通过array.filter()实现数组的数据筛选、数据清洗和链式调用

       通过Array.sort() 实现多字段排序、排序稳定性、随机排序洗牌算法、优化排序性能

       通过MongoDB Atlas 实现语义搜索与 RAG——迈向AI的搜索机制

       TreeSize:免费的磁盘清理与管理神器,解决C盘爆满的燃眉之急

       el-table实现动态数据的实时排序,一篇文章讲清楚elementui的表格排序功能

       深入理解 JavaScript 中的 Array.find() 方法:原理、性能优势与实用案例详解

       MutationObserver详解+案例——深入理解 JavaScript 中的 MutationObserver

       Dockerfile全面指南:从基础到进阶,掌握容器化构建的核心工具

       在线编程实现!如何在Java后端通过DockerClient操作Docker生成python环境

       干货含源码!如何用Java后端操作Docker(命令行篇)

目录
打赏
0
0
0
0
8
分享
相关文章
JavaScript 中通过Array.sort() 实现多字段排序、排序稳定性、随机排序洗牌算法、优化排序性能,JS中排序算法的使用详解(附实际应用代码)
Array.sort() 是一个功能强大的方法,通过自定义的比较函数,可以处理各种复杂的排序逻辑。无论是简单的数字排序,还是多字段、嵌套对象、分组排序等高级应用,Array.sort() 都能胜任。同时,通过性能优化技巧(如映射排序)和结合其他数组方法(如 reduce),Array.sort() 可以用来实现高效的数据处理逻辑。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
JavaScript中通过array.map()实现数据转换、创建派生数组、异步数据流处理、复杂API请求、DOM操作、搜索和过滤等,array.map()的使用详解(附实际应用代码)
array.map()可以用来数据转换、创建派生数组、应用函数、链式调用、异步数据流处理、复杂API请求梳理、提供DOM操作、用来搜索和过滤等,比for好用太多了,主要是写法简单,并且非常直观,并且能提升代码的可读性,也就提升了Long Term代码的可维护性。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
通过array.some()实现权限检查、表单验证、库存管理、内容审查和数据处理;js数组元素检查的方法,some()的使用详解,array.some与array.every的区别(附实际应用代码)
array.some()可以用来权限检查、表单验证、库存管理、内容审查和数据处理等数据校验工作,核心在于利用其短路机制,速度更快,节约性能。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
通过array.every()实现数据验证、权限检查和一致性检查;js数组元素检查的方法,every()的使用详解,array.some与array.every的区别(附实际应用代码)
array.every()可以用来数据验证、权限检查、一致性检查等数据校验工作,核心在于利用其短路机制,速度更快,节约性能。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
JavaScript中闭包详解+举例,闭包的各种实践场景:高级技巧与实用指南
闭包是JavaScript中不可或缺的部分,它不仅可以增强代码的可维护性,还能在模块化、回调处理等场景中发挥巨大作用。然而,闭包的强大也意味着需要谨慎使用,避免潜在的性能问题和内存泄漏。通过对闭包原理的深入理解以及在实际项目中的灵活应用,你将能够更加高效地编写出简洁且功能强大的代码。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
前端网络、JavaScript优化以及开发小技巧
YSlow有23条规则,中文可以参考这里。这几十条规则最主要是在做消除或减少不必要的网络延迟,将需要传输的数据压缩至最少。
前端网络、JavaScript优化以及开发小技巧
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
162 2
JavaScript中的原型 保姆级文章一文搞懂
本文详细解析了JavaScript中的原型概念,从构造函数、原型对象、`__proto__`属性、`constructor`属性到原型链,层层递进地解释了JavaScript如何通过原型实现继承机制。适合初学者深入理解JS面向对象编程的核心原理。
68 1
JavaScript中的原型 保姆级文章一文搞懂
|
5月前
JS+CSS3文章内容背景黑白切换源码
JS+CSS3文章内容背景黑白切换源码是一款基于JS+CSS3制作的简单网页文章文字内容背景颜色黑白切换效果。
44 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等