javascript 函数定义-我眼中的 JavaScript 函数式编程

2023-08-23 0 5,647 百度已收录

JavaScript 函数编程是一个已经存在很长时间的话题,但从 2016 年开始,它变得越来越流行。

这可能是由于 ES6 语法对函数编程更加友好,也可能是由于 RxJS(ReactiveX)等函数式框架的流行。

我看过很多关于函数式编程的解释,大部分都停留在理论层面,还有一些只针对Haskell等纯函数式编程语言。

本文致力于谈谈我眼中的JavaScript函数式编程的具体实践。 之所以是“在我眼里”,即我所说的仅代表我个人的观点,可能与一些严格的概念相冲突。

本文将省略大量形式化概念的介绍,重点讨论什么是 JavaScript 中的函数式代码,函数式代码与通常的写法有什么区别,使用函数式代码可以给我们带来什么,以及常见的一些函数式模型有哪些的 。

我理解的函数式编程

我认为函数式编程可以理解为一种以函数为主要载体的编程方法,利用函数对常用表达式进行拆解和抽象。

与命令式相比,这有多有用? 主要有以下几点:

下面的例子是一个具体的函数表达式:

当情况变得越来越复杂时,表达式的写法会遇到几个问题:

函数式编程很好地解决了上述问题。

首先参考函数式写法一,采用函数封装的方式将函数拆解(精细度不唯一),封装成不同的函数,然后借助组合调用达到目的。 这样做可以提高清晰度并促进维护、重用和扩展。

其次,Array.map借助高阶函数代替for...of进行链表遍历,减少中间变量和操作。

函数式编写方法1和函数式编写方法2的主要区别在于,你可以考虑以后函数是否可以复用。 如果不是,则前者更好。

链条优化

从前面的函数式编写方法我们可以看到,在函数式代码的编写过程中,很容易导致纵向扩展,即形成多层嵌套。 下面我们举一个更极端的反例。

这个例子仅展示了垂直延伸的更极端的情况。 随着函数嵌套层数的增加,代码的可读性急剧增加,并且很容易形成错误。

在这些情况下,我们可以考虑各种优化方法,比如下面的链式优化。

console.log(utils.chain(1).sum(2).sum(3).sub(4).value());

这样重写后,整体结构会显得更加清晰,而且链条上的每个环节在做什么也很容易解读。

函数嵌套和链接之间比较的另一个很好的例子是反弹函数和 Promise 模式。

由于反弹函数的嵌套层级和双层复杂度降低,会显得臃肿且不可维护,而Promise的链式结构在复杂度较高时仍然可以水平扩展,层次隔离非常清晰。

通用函数式编程模型

关闭

可以防止局部变量被释放的代码块称为闭包。

闭包的概念比较具体,相信大家或多或少都知道并使用过这个特性。

这样的关闭能给我们带来什么好处呢?

我们首先看一下如何创建闭包:

在makeCounter函数的代码块中,在返回的函数中,引用了局部变量k,导致函数执行后局部变量无法被系统回收,从而形成闭包。 这个闭包的作用是“保留”局部变量,以便调用外层函数时可以重用该变量; 与全局变量不同,该变量只能在函数内部引用。

换句话说,闭包似乎创建了一些函数私有的“持久变量”。

所以从这个反例我们可以得出结论:创建闭包的条件是存在内部函数和外部函数,并且外部函数引用了外部函数的局部变量。

闭包的主要目的是定义一些范围有限的持久变量,可以用于缓存或估计中间量。

里面的例子是一个简单的缓存工具的实现。 匿名函数创建了一个闭包,这样store对象仍然可以被引用并且不会被回收。

关闭是有其后果的。 持久变量通常不会被释放,并且持续占用显存空间很容易导致显存的浪费,因此通常需要一些额外的自动清除机制。

高阶函数

接受或返回函数的函数称为高阶函数。

听起来是一个很冷酷的词,但显然我们经常使用它,只是之前我们不知道它的名字。 JavaScript 语言本身支持高阶函数。 由于 JavaScript 函数是一等公民,因此它可以用作另一个函数的参数或返回值。

我们在JavaScript中经常可以看到很多原生的高阶函数,比如Array.map、Array.reduce、Array.filter。

我们以map(映射)为例,看看它是如何使用的。

映射是针对集合的,即对集合中的每一项进行相同的变换,形成一个新的集合。 map 是一个高阶函数,它接受函数参数作为映射的逻辑。

通常的写法中javascript 函数定义,以for...of循环的形式遍历字段会产生额外的操作,并且存在改变原有字段的风险,而map函数封装了必要的操作,这样我们只需要关心映射逻辑的函数实现,这会减少代码量并增加副作用的风险。

柯里化

给定函数的一些参数,生成一个接受其他参数的新函数。

您可能不经常看到这个术语,但任何使用过 undescore 或 lodash 的人都见过它。 有一个神奇的 _.partial 函数javascript 函数定义,它就是柯里化的实现。

通过_.partial,我们得到了一个新函数relativeFromBase。 该函数相当于调用时调用path.relative,第一个参数默认传递给BASE,后续参数的顺序在前。

在这个例子中,我们真正想要完成的是每次获取相对于 BASE 的路径,而不是相对于任何路径。 柯里化可以让我们只关心函数的一些参数,使得函数的目的更加清晰,调用也更加容易。

作品

组合多个函数的功能来创建一个新函数。

同样,你第一次看到它可能是在lodash中,compose方法(现在称为flow)。

_.flow结合了转换小写和转换为Base64的功能,生成一个新的函数。 方便作为参数函数或者后续复用。

自己的观点

我理解的JavaScript函数式编程可能和很多传统概念不一样。 我不只是认为高级函数算作函数式编程。 其他的,比如普通的函数组合调用、链式结构等,我认为都属于函数式编程的范畴,只要是以函数为主要载体的。

而且我不认为函数式编程是必要的,也不应该是强制性的要求或要求。 它是这些方法以及面向对象或其他想法之一。 更多的情况下,我们应该是几种的组合,而不是局限于概念。

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 javascript javascript 函数定义-我眼中的 JavaScript 函数式编程 https://www.wkzy.net/game/144542.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务