当前位置: 首页 > article >正文

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

目录

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

一、什么是柯里化?

1、原理解析

2、一个直观的例子

二、如何实现柯里化?

1、底层实现

2、工作原理解析

3、测试我们的实现

三、柯里化的优点

1. 参数复用

2. 延迟执行

3. 函数组合

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

五、实际应用场景

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

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

3. 深度嵌套函数的优化

六、总结


作者:watermelo37

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

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

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

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

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

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

一、什么是柯里化?

1、原理解析

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

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

2、一个直观的例子

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

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

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

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

        甚至可以分步调用:

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

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

        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));
      };
    }
  };
}

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

三、柯里化的优点

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!

2. 延迟执行

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

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

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

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

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

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

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

五、实际应用场景

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}`);

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

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); // 输出处理后的字数

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

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);

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

六、总结

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

        从 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(命令行篇)


http://www.kler.cn/a/449094.html

相关文章:

  • Oracle Database 21c Express Edition数据库 和 Sqlplus客户端安装配置
  • 语音增强的损失函数选择
  • C的编译过程有哪些步骤?
  • 《庐山派从入门到...》板载按键启动!
  • Vue(二)
  • 全志H618 Android12修改doucmentsui选中图片资源详情信息
  • 【PyQt5 02】基本功能(示例)
  • 作业:循环比赛日程表 与 取余运算(mod)
  • TensorFlow和Keras的区别和关系
  • GitCode 光引计划投稿|智能制造一体化低代码平台 Skyeye云
  • /etc/fstab 文件学习systemd与该文件关系
  • 开发整合笔记
  • 华为IPD流程6大阶段370个流程活动详解_第二阶段:计划阶段 — 86个活动
  • 基于Springboot的数字科技风险报告管理系统
  • 百度热力图数据处理,可直接用于论文
  • 层次聚类算法的研究
  • 江苏计算机专转本 技能Mysql知识点总结(三)
  • CTF-WEB php-Session 文件利用 [第一届国城杯 n0ob_un4er 赛后学习笔记]
  • open Feign服务抽取
  • 深入了解蓝牙Profile类型与设备的对应关系
  • SpringCloud 入门(2)—— 跨服务调度
  • 详细指南:如何手动卸载 Ubuntu 20.04 中源码编译安装的 OpenCV
  • 【华为OD-E卷-最左侧冗余覆盖子串 100分(python、java、c++、js、c)】
  • 如何让企业研发设计团队低配电脑流畅做3D大装配设计?
  • 【VScode】第三方GPT编程工具-CodeMoss安装教程
  • Webrtc音频模块(四) 音频采集