摘要:在学习的过程中时常会听到一个名次函数式编程,那么究竟什么是函数式编程,函数式编程又有什么优点,这就在这篇博客进行一个简单的总结吧主要内容函数式编程的概念函数式编程的优点与示例什么是函数式编程首先,我们放下编程的概念,我们来看函数。
在学习 JS 的过程中时常会听到一个名次——“函数式编程”,那么究竟什么是函数式编程,函数式编程又有什么优点,这就在这篇博客进行一个简单的总结吧~
主要内容:
函数式编程的概念
函数式编程的优点与示例
什么是函数式编程首先,我们放下编程的概念,我们来看函数。
函数的概念来自于数学,数学中的函数 f(x) = y 有一个非常重要的特点对于一个给定的 x,有唯一的 y 与其对应(这就是为什么椭圆曲线不是函数)
然而在编程中,函数并不具有这个特点,举个栗子:
let val = 1
function add(x){
return x + val
}
console.log(add(1)) // 2
val += 1
console.log(add(1)) // 3
可以看到编程中的函数在参数相同的情况下,允许有不同的返回值——只要依赖于函数外部的量
那么当函数依赖于外部的变量(常量不会有这样的问题),并且函数在多处调用,就有可能出现 bug,函数的调用结果可能会和预期结果相去甚远
而函数式编程就要求我们规避这样的情况,让所有函数对于相同的输入的返回值相同,这样的特性就叫做引用透明性,这就是函数式编程的核心特性!
一个符合引用透明性的函数的栗子:
function id(x){ return x; }
函数式编程带来的优点
在上文中提到过,编程语言中的函数大多是不满足数学中的函数的概念的,so 我们将满足数学函数条件的函数称为“纯函数”
可测试性函数式编程的优点大多都来自于纯函数
除了测试人员进行的全方位测试外,我们在开发过程中往往要对自己写的代码进行模块测试
在开发中,我受非纯函数迫害已久,由于它依赖了外部变量(比如存储在 localStorage 中的数据)我不得不三番五次去检查这些外部变量是否在某个过程中被改变甚至是删除
let val = 1
function add(x){
return x + val
}
console.log(add(1)) // 2
// 在未知因素影响下 val被改变
console.log(add(1)) // 预期结果 2,实际输出 emmmmm
如果我没有注意外部依赖而是一头扎进函数逻辑里,可能永远都找不到这个bug
代码的并发性虽然我们都知道 JS 是一门单线程语言(关于JS的执行可以参见->技术总结——JS的执行顺序),但是我们为了提高前端的性能可能会通过 WebWorker 来并发执行多个任务,或者在 Node 环境下 JS 并发执行函数
这个时候就是对非纯函数的一个很大的考验:
let global = "全局变量"
let func1 = ()=>{
global = "全局变量被改变了"
// 一些逻辑
}
let func2 = ()=>{
if(global = "全局变量"){
return true
}
}
上面的两个函数都依赖于外部的global,当它们并发执行,func1就会对func2产生影响,如果将它们变为纯函数就不会有这样的问题:
let global = "全局变量"
let func1 = (x)=>{
x = "全局变量被改变了"
// 一些逻辑
}
let func2 = (x)=>{
if(x = "全局变量"){
return true
}
}
函数执行的缓存
当我们的函数都是纯函数,而我们又会多次调用函数,我们就可以对函数对象进行一个缓存
比如我们需要大量计算数字的4次方,我们可以建立一个映射表用来缓存函数的执行结果:
// 映射表
let fourTimesTable = {};
let fourTimes = (x){
return x*x*x*x
}
// 检查表中是否有 2 的四次方,如果有就返回,如果没有就执行函数避免运算
fourTimesTable.hasOwnProperty(2)");2]:
fourTimesTable[2] = fourTimes(2)
管道与组合
管道过滤器是一种很经典的设计模式,我们可以将这种模式和函数式编程结合起来
在管道和过滤器软件体系结构中,每个模块都有一组输入和一组输出。每个模块从它的输入端接收输入数据流,在其内部经过处理后,按照标准的顺序,将结果数据流送到输出端,以达到传递一组完整的计算结果实例的目的。
在这种结构中,各模块之间的连接器充当了数据流的导管,将一个过滤器的输出传到下一个过滤器的输入端。所以,这种连接器称为“管道”。
我们也可以将这样的私用运用在函数式编程中,将一个个函数作为过滤器,通过函数的组合,形成一条数据处理的通路:
// 参数累加
function add(...args){
let result = args.reduce((prev, cur, index, arr)=> {
return prev + cur;
})
return result
}
// 参数累乘
function times(...args){
let result = args.reduce((prev, cur, index, arr)=> {
return prev * cur;
})
return result
}
let arr1=[1,3,6],arr2=[2,5,21],arr3=[3,7,8,27,4]
// 三组数据,要求组内累乘,然后结果累加
add(times(...arr1),times(...arr2),times(...arr3))
// 三组数据,要求组内累加,然后结果累乘
times(add(...arr1),add(...arr2),add(...arr3))
对函数式编程的初探暂止于此,进一步学习后再做总结~
本文同步发布于我的个人博客,CSDN,掘金
如果有什么问题,意见,建议欢迎评论;如果觉得我写的不错,那就点个赞吧~
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/7847.html
摘要:遍历执行其中存储的所有的匿名函数。如果我们使用一个类来管理相关依赖,这很接近的表现方式代码看起来就像下面这样你会发现现在匿名函数被储存在而不是原来的。 许多前端框架(如Angular,React,Vue)都有自己的响应式引擎。通过理解如何响应,提议提升你的开发能力并能够更高效地使用JS框架。本文中构建的响应逻辑与Vue的源码是一毛一样的! 响应系统 初见时,你会惊讶与Vue的响应系统。...
摘要:接收用户请求并分析请求的。执行函数并生成响应,返回给浏览器。这个过程我们称为注册路由,路由负责管理和函数之间的映射,而这个函数则被称为视图函数。文件是一个名为的文本文件,它存储了项目中提交时的忽略文件规则清单。 flask简述 Flask 是一个基于 Python 开发并且依赖 jinja2 模板和 Werkzeug WSGI 服务的一个微型框架,对于 Werkzeug 本质是 Soc...
摘要:系列教程,持续更新系列教程应用初见系列教程处理静态文件系列教程使用模板引擎系列教程路由控制中间件系列教程综合搭建登录注册页面系列教程实现登录注册功能这篇教程主要介绍构建服务器,简单引用本教程的版本要格外注意版本号案例简单利用搭建服务器文件夹 koa2系列教程,持续更新 koa2系列教程:koa2应用初见 koa2系列教程:koa2处理静态文件 koa2系列教程:koa2使用模板引擎 ...
阅读 2439·2021-09-29 09:34
阅读 3272·2021-09-23 11:21
阅读 2471·2021-09-06 15:00
阅读 1102·2019-08-30 15:44
阅读 2004·2019-08-29 17:23
阅读 2966·2019-08-29 16:44
阅读 3028·2019-08-29 13:13
阅读 1913·2019-08-28 18:12