面试官:什么是函数柯里化,能手写实现吗。

js 函数柯里化与连续调用函数实现相加 一、前言 面试的时候遇到一道题目: 实现sum函数,满足以下条件。 sum(1,2,3).valueOf() // 6 sum(1,2,3)(4).valueOf() // 10 sum(1,2,3)(4).valueOf() // 10 sum(1)(2)(3)(4)(5).valueOf() // 15 咋一看很熟悉,像那个什么返回函数的函数。有那么一瞬间想到是柯里化,但对其... 阅读详情

什么是函数柯里化

在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。这个技术以逻辑学家 Haskell Curry 命名的。

什么意思?简单来说,柯里化是一项技术,它用来改造多参数的函数。比如:


// 这是一个接受3个参数的函数
const add = function(x, y, z) {
return x + y + z
}

我们将它变换一下,可以得到这样一个函数:


// 接收一个单一参数
const curryingAdd = function(x) {
// 并且返回接受余下的参数的函数
return function(y, z) {
return x + y + z
}
}

这样有什么区别呢?从调用上来对比:


// 调用add
add(1, 2, 3)
// 调用curryingAdd
curryingAdd(1)(2, 3)
// 看得更清楚一点,等价于下面
const fn = curryingAdd(1)
fn(2, 3)

可以看到,变换后的的函数可以分批次接受参数,先记住这一点,下面会讲用处。甚至fn(curryingAdd返回的函数)还可以继续变换:


const curryingAdd = function(x) {
return function(y) {
return function(z) {
return x + y + z
}
}
}
// 调用
curryingAdd(1)(2)(3)
// 即
const fn = curryingAdd(1)
const fn1 = fn(2)
fn1(3)

上面的两次变换过程,就是函数柯里化。

简单讲就是把一个多参数的函数f,变换成接受部分参数的函数g,并且这个函数g会返回一个函数h,函数h用来接受其他参数。函数h可以继续柯里化。就是一个套娃的过程~

那么费这么大劲将函数柯里化有什么用呢?

2 柯里化的作用和特点

2.1 参数复用

工作中会遇到的需求:通过正则校验电话号、邮箱、身份证是否合法等等

于是我们会封装一个校验函数如下:


/**
* @description 通过正则校验字符串
* @param {RegExp} regExp 正则对象
* @param {String} str 待校验字符串
* @return {Boolean} 是否通过校验
*/
function checkByRegExp(regExp, str) {
return regExp.test(str)
}

假如我们要校验很多手机号、邮箱,我们就会这样调用:


// 校验手机号
checkByRegExp(/^1\d{10}$/, '15152525634');
checkByRegExp(/^1\d{10}$/, '13456574566');
checkByRegExp(/^1\d{10}$/, '18123787385');
// 校验邮箱
checkByRegExp(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/, 'fsds@163.com');
checkByRegExp(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/, 'fdsf@qq.com');
checkByRegExp(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/, 'fjks@qq.com');

貌似没什么问题,事实上还有改进的空间

  1. 校验同一类型的数据时,相同的正则我们写了很多次。
  2. 代码可读性较差,如果没有注释,我们并不能一下就看出来正则的作用

我们试着使用函数柯里化来改进:


// 将函数柯里化
function checkByRegExp(regExp) {
return function(str) {
return regExp.test(str)
}
}

于是我们传入不同的正则对象,就可以得到功能不同的函数:


// 校验手机
const checkPhone = curryingCheckByRegExp(/^1\d{10}$/)
// 校验邮箱
const checkEmail = curryingCheckByRegExp(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/)

现在校验手机、邮箱的代码就简单了,并且可读性也增强了


// 校验手机号
checkPhone('15152525634');
checkPhone('13456574566');
checkPhone('18123787385');
// 校验邮箱
checkEmail('fsds@163.com');
checkEmail('fdsf@qq.com');
checkEmail('fjks@qq.com');

这就是参数复用:我们只需将第一个参数regExp复用,就可以直接调用有特定功能的函数

通用函数(如checkByRegExp)解决了兼容性问题,但也会带来使用的不便,比如不同的应用场景需要传递多个不同的参数来解决问题

有的时候同一种规则可能会反复使用(比如校验手机的参数),这就造成了代码的重复,利用柯里化就能够消除重复,达到复用参数的目的。

柯里化的一种重要思想:降低适用范围,提高适用性

2.2 提前返回

在JS DOM事件监听程序中,我们用addEventListener方法为元素添加事件处理程序,但是部分浏览器版本不支持此方法,我们会使用attachEvent方法来替代。

这时我们会写一个兼容各浏览器版本的代码:


/**
* @description:
* @param {object} element DOM元素对象
* @param {string} type 事件类型
* @param {Function} fn 事件处理函数
* @param {boolean} isCapture 是否捕获
* @return {void}
*/
function addEvent(element, type, fn, isCapture) {
if (window.addEventListener) {
element.addEventListener(type, fn, isCapture)
} else if (window.attachEvent) {
element.attachEvent("on" + type, fn)
}
}

我们用addEvent来添加事件监听,但是每次调用此方法时,都会进行一次判断,事实上浏览器版本确定下来后,没有必要进行重复判断。

柯里化处理:


function curryingAddEvent() {
if (window.addEventListener) {
return function(element, type, fn, isCapture) {
element.addEventListener(type, fn, isCapture)
}
} else if (window.attachEvent) {
return function(element, type, fn) {
element.attachEvent("on" + type, fn)
}
}
}
const addEvent = curryingAddEvent()
// 也可以用立即执行函数将上述代码合并
const addEvent = (function curryingAddEvent() {
...
})()

现在我们得到的addEvent是经过判断后得到的函数,以后调用就不用重复判断了。

这就是提前返回或者说提前确认,函数柯里化后可以提前处理部分任务,返回一个函数处理其他任务

另外,我们可以看到,curryingAddEvent好像并没有接受参数。这是因为原函数的条件(即浏览器的版本是否支持addEventListener)是直接从全局获取的。逻辑上其实是可以改成:


let mode = window.addEventListener ? 0 : 1;
function addEvent(mode, element, type, fn, isCapture) {
if (mode === 0) {
element.addEventListener(type, fn, isCapture);
} else if (mode === 1) {
element.attachEvent("on" + type, fn);
}
}
// 这样柯里化后就可以先接受一个参数了
function curryingAddEvent(mode) {
if (mode === 0) {
return function(element, type, fn, isCapture) {
element.addEventListener(type, fn, isCapture)
}
} else if (mode === 1) {
return function(element, type, fn) {
element.attachEvent("on" + type, fn)
}
}
}

当然没必要这么改~

2.3 延迟执行

事实上,上述正则校验和事件监听的例子中已经体现了延迟执行。

curryingCheckByRegExp函数调用后返回了checkPhone和checkEmail函数

curringAddEvent函数调用后返回了addEvent函数

返回的函数都不会立即执行,而是等待调用。

3 封装通用柯里化工具函数

上面我们对函数进行柯里化都是手动修改了原函数,将add改成了curryingAdd、将checkByRegExp改成了curryingCheckByRegExp、将addEvent改成了curryingAddEvent。

难道我们每次对函数进行柯里化都要手动修改底层函数吗?当然不是

我们可以封装一个通用柯里化工具函数(面试手写代码)


/**
* @description: 将函数柯里化的工具函数
* @param {Function} fn 待柯里化的函数
* @param {array} args 已经接收的参数列表
* @return {Function}
*/
const currying = function(fn, ...args) {
// fn需要的参数个数
const len = fn.length
// 返回一个函数接收剩余参数
return function (...params) {
// 拼接已经接收和新接收的参数列表
let _args = [...args, ...params]
// 如果已经接收的参数个数还不够,继续返回一个新函数接收剩余参数
if (_args.length < len) {
return currying.call(this, fn, ..._args)
}
// 参数全部接收完调用原函数
return fn.apply(this, _args)
}
}

这个柯里化工具函数用来接收部分参数,然后返回一个新函数等待接收剩余参数,递归直到接收到全部所需参数,然后通过apply调用原函数。

现在我们基本不用手动修改原函数来将函数柯里化了


// 直接用工具函数返回校验手机、邮箱的函数
const checkPhone = currying(checkByRegExp(/^1\d{10}$/))
const checkEmail = currying(checkByRegExp(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/))

但是上面事件监听的例子就不能用这个工具函数进行柯里化了,原因前面说了,因为它的条件直接从全局获取了,所以比较特殊,改成从外部传入条件,就能用工具函数柯里化了。当然没这个必要,直接修改原函数更直接、可读性更强

4 总结和补充

  1. 柯里化突出一种重要思想:降低适用范围,提高适用性
  2. 柯里化的三个作用和特点:参数复用、提前返回、延迟执行
  3. 柯里化是闭包的一个典型应用,利用闭包形成了一个保存在内存中的作用域,把接收到的部分参数保存在这个作用域中,等待后续使用。并且返回一个新函数接收剩余参数
【Stata双重差分模型】双重差分DID的具体操作步骤 本案例将详细阐述如何使用双重差分法进行实证分析,并展示具体的STATA操作代码。 阅读详情

相关推荐

避坑指南:Python模拟抖音扫码登录时,那些你可能会遇到的‘Referer’和‘Token’校验问题

本文深入解析Python模拟抖音扫码登录时常见的Referer校验与Token失效问题,提供五大陷阱的解决方案。从动态fp参数生成到Referer校验策略,再到Token生命周期管理,手把手教你破解抖音登录接口的反爬机制,助力开发者高效完成自动化登录。

weixin_42573113的博客 780

前端面试手写代码——JS函数柯里化

1 什么是函数柯里化 2 柯里化的作用和特点 2.1 参数复用 2.2 提前返回 2.3 延迟执行 3 封装通用柯里化工具函数 4 总结和补充

qq_38650754的博客 566

手把手教你:如何为自制的STM32H7飞控板适配PX4固件(基于NuttX)

本文详细介绍了如何为自制的STM32H7飞控板适配PX4固件,基于NuttX系统进行移植。从硬件设计规范到软件环境配置,再到PX4固件的移植与调试,提供了完整的实战指南。特别分享了如何复用FMU-v6u参考设计以节省开发时间,并解决了常见问题,帮助开发者快速实现高性能飞控系统的搭建。

weixin_27697385的博客 475

【js手写系列】js函数柯里化

如何封装函数柯里化: 思路: 首先目标是一个以一个函数作为参数,返回这个函数的柯里化函数的函数 闭包把目前已经输入的参数存在一个数组里 如果参数量不够,直接返回同一个函数(arguments.callee指函数本身) 如果参数量够了,直接执行传入的函数

weixin_47520173的博客 434

3D-IC测试挑战与Tessent解决方案解析

3D-IC技术通过硅通孔(TSV)实现芯片垂直堆叠,是延续摩尔定律的关键路径。该技术面临三大核心挑战:KGD标准严苛化要求测试覆盖率达99.5%以上,存储器测试需兼容LPDDR/HBM等多种协议,逻辑堆叠需解决TSV互连的电气特性和时序验证问题。Mentor Tessent平台采用混合测试架构,结合压缩扫描测试(ATPG)和内建自测试(BIST)技术,实现100x测试数据压缩比和99.97%的TSV缺陷检出率。这些创新方案在移动SoC和高性能计算芯片中已获验证,测试时间缩短73%,缺陷逃逸率降低77%。随着

weixin_30621711的博客 376

LIN总线从入门到精通:低成本汽车通信协议原理与实战

在汽车电子和嵌入式系统中,串行通信协议是实现分布式控制的关键技术。其中,LIN(Local Interconnect Network)总线作为一种专为低成本应用设计的单主多从网络协议,其核心原理在于通过简化的“领导-汇报”通信模式,在满足车身控制、传感器数据采集等场景需求的同时,将硬件与布线成本降至最低。LIN总线采用标准化的帧结构,包含间隔场、同步场和受保护标识符场,并依赖调度表来管理通信时序,确保了网络的确定性与可靠性。其技术价值在于为车窗、座椅、灯光等非安全关键系统提供了高性价比的解决方案,是构建分层

weixin_29185167的博客 260

js函数柯里化

由于最近离职找工作的事情,好久不写文章了,就只好把2017年写的文章搬出来骗骗赞了hhh。 概念 用我自己的话来总结一下,函数柯里化的意思就是你可以一次传很多参数给curry函数,也可以分多次传递,curry函数每次都会返回一个函数去处理剩下的参数,一直到返回最后的结果。 实例 这里还是举几个例子来说明一下: 柯里化求和函数 // 普通方式 ...

weixin_34074740的博客 271

如何使用VNC对openEuler系统进行远程图形化操作

本文详细介绍了在openEuler系统中配置VNC远程图形化操作的方法。主要内容包括:1)服务端配置:安装GNOME图形界面和TigerVNC服务,创建VNC用户并设置密码,配置VNC服务启动脚本;2)客户端连接:使用VNC Viewer等工具连接服务器;3)常见问题解决方法。通过5901端口建立连接后,用户可远程操作openEuler图形界面,适用于需要图形化管理的场景。

2501_93651177的博客 313

JS函数柯里化

柯里化 JS

web$-小白 4752

《驾驭你的AI同事:WorkBuddy深度精通》027:11.1 私有知识库接入

11.1 私有知识库接入 —— 《驾驭你的AI同事:WorkBuddy深度精通》系列图文教程,配图已统一为规范示意图。

LuckyHanMo的博客 135

Android 13.0 双屏时触摸失效问题排查与修复

摘要:本文记录了RK3588 Android12开发板上主屏触摸失效问题的排查与解决过程。通过分析发现,USB触摸设备被错误关联到辅屏(displayId=3)而非主屏(displayId=0)。解决方案是修改TouchInputMapper.cpp,强制触摸设备使用INTERNAL viewport(主屏),并保持设备在viewport不活跃时仍启用。该修改涉及约40行代码,有效解决了多显示器环境下触摸设备错误映射的问题,同时提供了详细的调试方法和注意事项。

ip0417的博客 352

【JavaScript 手写】-- 函数柯里化

函数柯里化: 其实就是将使用多个参数的函数转换成一系列使用一个参数的函数的技术 例如: function add(a, b, c) { return a + b + c } add(1, 2, 3) let addCurry = curry(add) addCurry(1)(2)(3) 实现: function curry(fn) { let loop = (...arg) => { if (arg.length === fn.length) retur

野生松 523

数据资产可视化分析:PowerBI在大数据管理中的实战

目的:帮你搞懂“为什么数据资产需要可视化?”“PowerBI能帮企业解决什么问题?”,并掌握用PowerBI做大数据可视化的实战技巧。范围:覆盖数据资产定义、可视化分析原理、PowerBI核心功能(数据连接、建模、可视化)、零售企业实战案例,以及未来趋势与挑战。背景:为什么企业的数据像乱堆的玩具?核心概念:数据资产、可视化分析、PowerBI分别是什么?它们怎么配合?实战步骤:用PowerBI帮零售企业整理“销售玩具箱”,做出能指导决策的仪表盘;应用场景:不同部门怎么用这个“整理好的玩具箱”?

2501_92132293的博客 906

面试官:什么是函数柯里化?能手写实现吗?

函数柯里化是将多参数函数转换为单参数函数链式调用的技术,具有参数复用、提前返回和延迟执行三大特点。通过封装通用柯里化工具函数,可以实现参数的部分应用,减少重复代码。典型案例包括正则校验复用和浏览器兼容性处理,其本质是利用闭包保存参数状态。柯里化的核心思想是“降低适用范围,提高适用性”,是函数式编程的重要技术。

青春木鱼的博客 967

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

【JavaScript】面试手撕柯里化函数

首先,我们参照维基百科给出的定义:在计算机科学中,柯里化(英语:Currying),又译为卡瑞化或加里化,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术举个🌰我们正常情况下写sum函数是如下的方式// 调用sum(1,2)但是柯里化后是这样实现的// 调用sum(1)(2)

鑫宝的博客 2420

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

面试官:请用JavaScript实现柯里化及其应用场景

你正在参加一场重要的技术面试,面试官问道:“你能解释一下什么是柯里化(Currying),并用JavaScript实现一个柯里化函数吗?此外,请解决几个相关的面试题。”这个问题不仅考察你对函数式编程的理解,还考察你将理论应用于实际代码的能力。什么是柯里化?你自信地回答:“柯里化(Currying)是一种函数式编程技术,它的核心思想是将一个接受多个参数的函数转换成一系列接受部分参数的函数链条。每次调...

前端达人 1029

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

面试常考的函数柯里化 curry 到底怎么写是最优解

函数柯里化(Currying)是函数式编程中的一个重要概念,它将一个接受多个参数的函数转换成一系列接受单一参数的函数。在面试中面试官经常使用这个题目来考察面试者的函数式编程理解、代码抽象能力、闭包和作用域理解这几方面的能力。想要写好函数柯里化,那么我们需要知道什么是柯里化。柯里化是一种关于函数的高阶技术。它不仅用于 JS,还被用于其他编程语言。它是一种函数的转换–>将一个函数从可调用的 转换为可调用的。。 下面来看一个例子: 熟悉闭包的同学或许一眼就看出来,这里利用了闭包的特性来实现了一个基础的柯里化函数。

fans_x的博客 625

面试官:怎么把函数柯里化?

点击上方程序员成长指北,关注公众号 回复1,加入高级Node交流群柯里化(Currying)是一种函数转换的技术,将接受多个参数的函数转化为一系列每次只接受一个参数的函数。在JavaScript中,这可以通过创建一个闭包来实现,使得每个函数调用都可以只接收一个参数并返回一个新的函数,直到所有参数都被接收为止。为什么需要柯里化柯里化的目的是提高代码的可重用性和灵活性,同时便于函数的组合和延迟执行。...

程序员成长指北 124

JavaScript之函数柯里化

参考资料 [面试官:什么是函数柯里化?能手写实现吗? - 蜜瓜 - 博客园 (cnblogs.com)](https://www.cnblogs.com/bidong/p/15498133.html#:~:text=在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数 (最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。 这个技术以逻辑学家 Haskell,Curry 命名的。 什么意思? 简单来说,柯里化是一项技术,它用来改造多参数的函数。)

fujiaxu666的博客 395

js中的函数柯里化思想

柯里化: 是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。 面试中嘴jian,提了一下函数柯里化思想,面试官反问我函数柯里化有哪些应用场景,回答了只知道bind的内部实现,还好面试官说在实际工作中也不常用,问题不大。不过名字叫得这么高大上,还是了解一下比较好。 概念过于抽象,看下面例子马上理解: // 普通的add函...

CC_Together的博客 435

函数式编程与柯里化-笔记

00-接上篇 在上一篇中主要记录了函数柯里化的基本概念和手动实现,当然如果在每一个项目中都手动实现一遍柯里化显然是不方便的。其次,函数柯里化在函数式编程中具体有哪些应用模式呢?本篇将主要讲述柯里化的使用和函数式编程的应用。 01-Lodash中的柯里化功能 lodash是一个一致性、模块化、高性能的 JavaScript 实用工具库。在其内部将我们生产和开发中的许多常用功能抽象成了各种函数以方便调用(虽然他们不一定都是纯函数),其中便提供了curry和curryRight方法,这一方法可以帮助我们将函数柯里

Here`s Chino 335

一道面试题教会你实现函数的柯里化

一道面试题教会你实现函数的柯里化

huihui_999的博客 398

面试让写一个“bind”函数,详解五层bind函数进阶写法,带你写出一个让面试官满意的 “bind” 函数

文章目录手写bind函数第一层 - 绑定在原型上的方法第二层 - 改变this的指向第三层 - 支持柯里化第四层 - 考虑 new 的调用第五层 - 保留函数原型总结最终版bind函数 手写bind函数 面试经常问到,能不能实现一个bind函数 当时立马写了一个无脑的bind function bind(fn, obj, ...arr) { return fn.apply(obj, arr) } 但是这种bind函数,一看就问题重重 函数柯里化怎么用? new 情况怎么办? 原型对象有考虑嘛? 要

秋天,黄叶坠地,凉风有信。 1560

【精解前端八股手写题】深入浅出柯里化

一行代码实现柯里化,大厂前端面试经典手写题目案例分析,精通柯里化与闭包,全面掌握概念、应用场景以及实现原理,做问不倒的最强前端应试者!

碳基蒟蒻Serio的博客 1138

高阶函数/柯里化/纯函数

本篇文章主要是介绍一下标题里面的概念,在面试的时候经常文档,结合阅读到的资料,结合本人的个人见解出品了该文章,如有写的不好的地方或理解有误的,还望阁下多多指教。

GodLoveMe的博客 396

【面试官问】你懂函数式编程吗?

面试官:你好,你有用过函数式编程吗? 我:函数式?没有呢? 面试官:那有了解过吗? 我:额。。。也没有,贵公司主要使用函数式编程么? 面试官:嗯,不怎么使用,但我就是想问 又到了面试的季节,相比很多小伙伴会被面试官一顿连环问,面试造火箭,进去拧螺丝,可想要顺利入职还是得硬着头皮把火箭造出来才行。 最近不定期写一些跟面试相关的知识点,为大伙的面试打气加油。 这篇我们说说函数式编程。 函数式编程是...

weixin_34318272的博客 711
上一篇: 技能篇:实际开发常用设计模式
下一篇: 深入剖析Redis客户端Jedis的特性和原理
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值