关于函数式编程的思考(1)

做者:李英杰,美团金融前端团队成员。欢迎你们一块儿来探讨FPjavascript

题外话:只是单纯地谈谈我的对函数式编程的理解,欢迎你们来一块儿探讨。也不会说起高阶函数与范畴学的内容,只聊一些很入门的问题。函数式编程的优势这里也不作过多说明,会推荐你们看几篇文章,里面有很好的阐述。

斜体灰字部分是一些我的的吐槽和私货

目录

  1. 为何函数式编程在前端复兴?前端

  2. 什么是函数式编程?java

  3. 函数式编程如何思考问题?react

  4. 函数式编程与面向对象编程有什么区别,各自的优缺点是什么?ajax

  5. map,reduce是函数式编程吗?编程

  6. 推荐redux


1.咱们来简单捋捋前端的发展。

  • 上古时代,所有都是静态页面
  • 有js了,你们能够在页面搞一搞简单的交互了
  • ajax来了,能够更加自由地作本身想作的事情了
  • 切图仔们不甘寂寞了,要搞事情,因而有了SPA后端

    好,咱们先停在这里了。SPA来了,咱们很开心,曾经的小人物能够尝试着作主人了,后端只要给接口咱们就能呈现出一个完整的网站了。然而没过多久咱们开始不开心了,能力越大责任越大,须要考虑的问题愈来愈多,问题也愈来愈复杂。其中一个比较关键的问题就是:数据与展现之间的关系咱们该如何处理?数组

按时间顺序,列几个我了解的SPA框架框架

Extjs --- MVC
Angular --- MVVM
React/Redux --- 单向数据流(好尴尬,别人都是英文字母)
各类MVW框架都在努力地帮助咱们理清数据与展现之间的关系。

发展到今天,展现方面React很流行了;数据处理方面,flux单向数据流的思想获得了你们的认同,基于flux思想的redux目前基本成为了复杂数据场景中react的标配。

不管是React仍是Redux,都或多或少提到了函数式编程。是它们参考了函数式编程,仍是在提出方案后发现与函数式编程比较搭,咱们先不深究。能够看到的是,前端当前的发展阶段在必定程度契合了函数式编程的思惟。
前端都是一群爱折腾的人,比较喜欢创造或建造一些东西。因此咱们可能不是很喜欢大而全的东西,而是喜欢搭积木。
React说:我只负责view,你能够自由选择处理data的伙伴
Redux说:我只负责data,你能够自由选择处理view的伙伴
因而——没法抗拒
而它们提到的函数式编程,又像是一个已经半开的宝藏大门,在勾引着咱们进去看看。必须认可,我也是看Redux入坑的。据我所知,像这样入坑的前端还很多。

函数式编程并非新的编程范式,只不过最近才走进了前端的视野。你们能够思考一下这个问题,特别是对其感兴趣的同窗——为何直到今天前端才想要了解函数式编程,函数式编程是否是在全部场景下适用?
咱们能够凭着兴趣和激情在全部场景下进行尝试,不过针对不一样的场景选择合理的解决方案才是咱们应该有的态度。好比:Redux做者也会说一句:或许你不须要Redux。

2.介绍完背景,能够正式发问了:什么是函数式编程?

前端方向上介绍函数式编程的文章和书籍对于定义给的都比较晦涩,或者干脆略过不写,只是写了些函数式编程的特色和优势。我的认为这对于前端同窗理解函数式编程形成了必定的困扰。
最初学习的时候我不能理解:
    为何相同输入对应同一输出
    为何输入的参数不能改变
    为何没有循环,只有递归
    为何提到函数式编程就提数学
他们只是告诉我这个东西就该是这样子的。

在解释以上问题以前,先抛出另外一个问题——什么是函数?
貌似是一个很白痴的问题,码农们怎么会不知道什么是函数,每天都在写函数的好很差。

再明确一下这个问题,“函数式编程”里的“函数”是什么?
这里面提到的“函数”是数学中的函数,不是编程中的函数。
数学中的函数是这样定义的:函数在数学中为两集合间的一种对应关系:输入值集合中的每项元素皆能对应惟一一项输出值集合中的元素。——选自维基百科

因此“函数”是这个样子的


也会是这个样子的

但不是这个样子的

function test(x, y) {
  console.log(x, y);
}复制代码

这是码农们的函数 :)

了解了这一点,结合以上两个函数的例子,你们能够思考一下刚刚提到的问题,应该很快就能够理解了。
    为何相同输入对应同一输出
    为何输入的参数不能改变
    为何没有循环,只有递归
    为何提到函数式编程就提数学

3.了解什么是函数编程,接下来就是咱们如何用函数式编程解决问题了

  • 将实际问题转换为数学问题
  • 小函数组合成大函数,大函数组成更大的函数,直至解决问题 —— 这里函数还是数学中的函数

用数学去解决问题有几点好处

  • 保证稳定的手段之一 ———— 数学是稳定的,关于数学为何是稳定的,这里就不作说明了:)
  • 可推导 ———— 数学函数运算

推导在咱们实际编程中有什么意义?
来看一个例子(这个例子是在其余书籍中看到的,只不过书籍的做者从其余角度分析了这个例子)

async({
  success: data => handleData(data),
  fail: () => alert('error)
})复制代码

async是一个异步函数,success和fail分别对应了该异步函数在成功和失败状况下的处理
从函数式的角度来思考一下如何优化
首先将程序中的函数用数学中的函数表示出来

而后咱们来根据函数的内容来推导一下

若是对于任意输入,函数f, g的输出都一致,那么f,g就是能够互相替换的。

对于这个例子来讲,咱们就能够写成这个样子

async({
  success: handleData,
  fail: () => alert('error)
})复制代码

再举一个例子,你们很是熟悉的小学应用题
应用题:
小雨带着n个苹果出去玩,路过薛大叔家,薛大叔给了她n个苹果,薛大婶给了她1个苹果
问题1:小雨如今有多少个苹果
路过张砖头家,小雨给了张砖头n个苹果
问题2:小雨如今有多少个苹果?
已知:
add(x, y) = x + y;
sub(x, y) = x - y;

能够很快速地给出答案
问题1:f(x) = add(add(x,x),1)

let n = 10;
let result = add(add(n, 1), 1);复制代码

问题2:g(x) = sub(f(x), x)

let result2 = sub(result, n);复制代码

实际中,咱们只是想知道问题2的结果。
问题1的存在可能有两个缘由

  • 咱们分解了开发过程
  • 最初咱们想要获得问题1的结果,随着业务的发展,如今咱们要获得问题2的结果

若是只是想要问题2的结果咱们就能够进行优化了,用一下你们都很熟悉的四则运算
sub(f(x),x) = f(x) - x = x + x + 1 - x = x + 1 = add(x, 1)
也就是说
sub(f(x), x) 等价于 add(x, 1)
最终
g(x) = add(x, 1)

let n = 10;
let result2 = add(n, 1);复制代码

好的,这就是咱们最终问题的答案了。

未完待续……


最后,团队为了招聘方便,整了个公众号,主要是一些招聘信息,团队信息,全部的技术文章在公众号里也能够看到,对了,若是你想去美团其余团队,咱们也能够帮你内推哦 ~

二维码
二维码
相关文章
相关标签/搜索