函数式编程探索(二) – 函数式编程与面向对象编程
面向对象编程是当前不可否认的应用最广泛的编程范式,函数式编程则从小众变得越来越热门,它们有哪些不同的地方,我从我了解的知识和使用过程中的感受来列几点。
发展史
函数式编程
实际上要早于面向对象编程,它来源于数学中的 Lambada
表达式,发明它是用来表达数学中演算式,它以逻辑性和简洁的特点,一直流行于学术界。
面向对象编程
出现在软件工程化发展进程中,在编程范式中属于命令式,与声明式相对,它的设计目的是为了软件的重用、灵活和扩展,主要特点是封装、继承和多态,在工业界广泛应用。
说明:本文讨论的面向对象编程是基于类的面向对象,其实
Javascript
也是面向对象的,它是基于原型的面向对象。
范式
函数式编程
属于声明式
,声明式的设计理念是告诉计算机我需要达到什么目标;
面向对象编程
属于命令式
,命令式的设计理念是告诉计算机我需要你做什么操作。
从字面上看,这么说很让人迷糊,计算机是一台机器,有什么主动和被动。我理解的是:什么语言都是编译成机器码,不存在主动被动。这里可以理解为我们写代码是给其他人阅读的和调用的,声明式代码看起来是要完成什么目标,比如数组的 filter
,就是按过滤函数过滤一个数组;命令式的代码看起来是要完成一个什么操作,比如 for
,就是执行循环语句。
我们先来看一个 Javascript
对比案例,感受一下有什么不同。
有这么一个需求,对于下面的 data
数据:
- 判断nums是不是空的,空的话找下一个;
- 如果nums不是空,就停,并拿它的id去和后台要资料;
- 如果全部的nums都是空的,就直接拿第一个的id去要资料。
let data = [ { nums: [], id: 1 }, { nums: ['222'], id: 3 },{ nums: [], id: 4 },{ nums: ['3213','33'], id: 5 } ]
命令式写法:
if(data.length>0){ let target = data[0] for(let index=0;index<data.length;index++){ let item = data[index] if(item.nums && item.nums.length > 0){ target = item break } } }
声明式写法:
const { id } = data.filter(item => item.nums && item.nums.length)[0] || data[0]
看上面两段代码,我们有个直观的感受:
- 声明式写法直观、简洁;
- 命令式写法对过程描述很清楚,更便于计算机阅读。
这个例子只是展示两种模式的思维方式的不同,声明式简洁,因为它使用了
filter
运算。
上述声明式写法已经用到了函数式编程,函数式编程在实践中总结出很多有用的运算,比如 map
,reduce
,filter
。
上述命令式写法其实还没用到高级的设计模式,面向对象在大型项目构建时比较有优势。
工程应用
工程应用领域,面向对象编程比较有优势,函数式只在少数领域有大型项目应用。
面向对象
目前大多数的企业服务,都是使用 Java 编写的,也就是说用的是面向对象的编程模式。可见面向对象的优势还是很明显的。我来列举一下:
- 建模
人类的认知模式就是渐进式的,从简单到复杂,从具体到抽象。面向对象的接口、类和继承非常容易对我们的认知进行建模,比如,我们做一个电商应用,那么肯定有这么几类对象:商店、商品、顾客、商家和订单等等,我们为每类对象创建一个类去描述它,类和类之间用关系连接起来,非常清晰。而且,商品是分很多品类的,那么我们再用继承来实现重用,基础的设计就这样完成了。再多一点,我们可以加上工厂模式去生产商品对象,非常好。 - 契约
企业项目一般都是分工协作的,分模块开发,根据契约对内、对外提供服务。面向对象中用接口定义契约非常方便,内部开发定义好契约就明确了代码功能和边界,外部拿到契约就知道如何调用服务。这样做可以实现规范设计、降低耦合和并行开发,大大提高协作效率。 - 设计模式
设计模式大家都不陌生,或多或少都会用到一些,使用设计模式可以让代码更简洁优美,重用性更好。不过这不能只算面向对象的优势,函数式编程也可以应用设计模式,只不过面向对象的广泛应用积累了很多很成熟的设计模式。
函数式
函数式编程在工程领域相对小众,在计算机理论界比较受欢迎,拥有很多骨灰级玩家。工程领域应用比较多的有 Erlang
(爱立信的电信系统就是用它写的,并发性、稳定性特别好),还有 scalar
(大数据处理框架 spark 是用它写的)。
函数式编程的优势在第一篇,提到了,主要这几点:
- 使用表达式,简洁
- 状态不可变,副作用可控
- 引用透明
这个概念比较抽象,我们可以来看看一个入门的例子。
首先,定义一个容器,有了这个容器,我们就可以方便的进行表达式运算。
var Container = function(x) { this.__value = x; } Container.of = function(x) { return new Container(x); } Container.prototype.map = function(f){ return Container.of(f(this.__value)) }
它有什么好处呢?
- 作为一个容器,存放数据
- 可以使用
map
添加数据处理器 - 可以链式调用
我们来看看示例,比如我们想把一个句子中每个单词的首字母取出来,转成大写字母并拼在一起。
Container.of('The quick brown fox jumps over the lazy dog.') .map(s => s.split(/\b/)) .map(s => s.map(w => w.trim().charAt(0)).join('')) .map(s => s.toUpperCase());
总结
函数式编程并不是银弹,也不应该引起类似“Php是最好的语言”的争论。应该根据实际场景使用,一个项目,可以使用函数式编程,也可以使用面向对象编程,也可以都用,它们都可以满足你的需求。
引用
欢迎交流
个人读书公众号,欢迎交流!
原文地址:https://segmentfault.com/a/1190000021363278
相关推荐
-
在单页应用中,如何优雅的监听url的变化 javascript/jquery
2018-12-31
-
snkrs web端分析,canvas中的fingerpint javascript/jquery
2019-11-1
-
前端工程化 – 剖析npm的包管理机制 javascript/jquery
2020-6-11
-
TYPESCRIPT指南(译文) javascript/jquery
2019-1-30
-
细说 JavaScript 七种数据类型,JavaScript 中的四舍五入,javascript类型系统——Number数字类型 javascript/jquery
2019-5-6
-
支付宝移动端 Hybrid 解决方案探索与实践 javascript/jquery
2019-8-24
-
张伦:巧用 webpack loader 实现项目的定制化 javascript/jquery
2019-6-7
-
JavaScript 进阶问题列表,你掌握了多少? javascript/jquery
2019-7-20
-
JS 中的offset、scroll、client总结 javascript/jquery
2018-8-12
-
浅探前端图片优化 javascript/jquery
2018-12-22