JavaScript 函数式编程究竟是个啥

随着大前端时代的到来,在产品开发过程当中,前端所占业务比重愈来愈大、交互愈来愈重。传统的老夫拿起JQuery就是一把梭应付当下重交互页面已经十分乏力。因而乎有了Angular,React,Vue这些现代框架。javascript

但随之而来的还有大量的新知识新名词,如MVC,MVVM,Flux这些设计模式就弄得不少同窗傻傻分不清。这时候又见到别人讨论什么函数式编程,更是一脸懵逼了。html

咱们大多听过面向对象编程,面向过程编程,那啥又是函数式编程呢?在咱们前端开发中又有哪些应用场景?我抱着这个疑惑,初步的学习了下。(此文仅是学习,无甚干货)。前端

函数式编程

定义

函数式编程(Functional Programming,后面简称FP),维基百科的定义是:java

是一种编程范型,它将电脑运算视为数学上的函数计算,而且避免使用程序状态以及易变对象。函数编程语言最重要的基础是λ演算(lambda calculus)。并且λ演算的函数能够接受函数看成输入(引数)和输出(传出值)。比起命令式编程,函数式编程更增强调程序执行的结果而非执行的过程,倡导利用若干简单的执行单元让计算结果不断渐进,逐层推导复杂的运算,而不是设计一个复杂的执行过程。react

我来尝试理解下这个定义,好像就是说,在敲代码的时候,我要把过程逻辑写成函数,定义好输入参数,只关心它的输出结果。并且能够把函数做为输入输出。感受好像日常写js时,就是这样的嘛!编程

特性

网上FP的定义与特性琳琅满目。各类百科、博客、一些老师的网站上都有大同小异的介绍。为了方便阅读,我列下几个好像比较重要的特性,并附上个人第一眼理解。设计模式

  1. 函数是一等公民。就是说函数能够跟其余变量同样,能够做为其余函数的输入输出。喔,回调函数就是典型应用。数组

  2. 不可变量。就是说,不能用var跟let咯。按这要求,我彷佛有点难写代码。闭包

  3. 纯函数。就是没有反作用的函数。这个好理解,就是不修改函数外部的变量。框架

  4. 引用透明。这个也好理解,就是说一样的输入,一定是一样的输出。函数内部不依赖外部状态,如一些全局变量。

  5. 惰性计算。大意就是:一个表达式绑定的变量,不是声明的时候就计算出来,而是真正用到它的时候才去计算。

还有一些衍生的特性,如柯里化与组合,三言两语说不清,就不阐述了,有兴趣的同窗能够本身再了解了解。

FP在JavaScript中的应用

React就是典型的FP。它不一样于Vue这样的MVVM框架,它仅仅是个View层。
ReactView = render(data) 它只关心你的输入,最终给你返回相应视图。因此你休想在react组件中去修改父组件的状态,更没有与dom的双向绑定。

这个是框架上的应用,那么在咱们日常书写JavaScript时有哪些应用呢?换句话说,日常书写js时候,遇到什么状况,咱们采用FP会更好。

从最多见的入手吧,如典型的操做数组:

// 从users中筛选出年龄大于15岁的人的名字
const users = [
  {
    age: 10,
    name: '张三',
  }, {
    age: 20,
    name: '李四'
  }, {
    age: 30,
    name: '王五'
  }
];

// 过程式
const names = [];
for (let i = 0; i < users.length; i++) {
  if (users[i].age > 15) {
    names.push(users[i].name);
  }
}
// 函数式
const names = users.filter(u => u.age > 15).map(u => u.name);

嗯,代码精简了不少,可是貌似带来了更大的开销。若是是很是大的数据,很是多的筛选工做,那就会循环屡次。

这里得想到刚刚的惰性计算。按照惰性求值的要求,应该是要最后返回结果时,才真正去筛选年纪并获得姓名数组。

然而JavaScript的数组并不支持惰性求值。这时候咱们得上一些工具库,如Lodash。能够看下它文档中的例子:_.chain

好像也没好到哪里去啊,不就是把多行代码变一行嘛?说的那么玄乎,还多了性能开销,而后又跟我说得上个工具库。。。

说的好像颇有道理,可是for循环是有个弊端的,它产生了变量i,而这个变量又是不可控的,若是业务逻辑一复杂,谁知道它循环到何时i有没有发生变化,而后致使循环出问题呢?

咱们再看一个与DOM交互的场景:
假如页面有一个按钮button,咱们须要求出用户点击了几回,可是一秒钟内重复点击的不算。传统方法会这么写。

var count = 0;
var rate = 1000;
var lastClick = Date.now() - rate;
var button = document.querySelector('button');
button.addEventListener('click', () => {
  if (Date.now() - lastClick >= rate) {
    console.log(`Clicked ${++count} times`);
    lastClick = Date.now();
  }
});

妥,彻底没问题。可是发现多了不少状态,count,rate,lastClick,还得对比来对比去。那若是用FP会是怎么样的呢?

抱歉。。。无法写。。。除非很强大的编程能力,本身封装好方法去处理。因此在这里,咱们能够上个工具---Rx.js,上述的例子就是rxjs中引用的,咱们看它是如何优雅地处理的。

var button = document.querySelector('button');
Rx.Observable.fromEvent(button, 'click')
  .throttleTime(1000) // 每隔1000毫秒才能触发事件
  .scan(count => count + 1, 0) // 求值,默认值是0
  .subscribe(count => console.log(`Clicked ${count} times`)); // 订阅结果、输出值

巧夺天工!不再用去管理状态了,不须要声明一堆变量,修改来修改去,判断来判断去,简直完美。

日常咱们有不少须要更新dom的异步操做,如搜索行为:用户连续输入查询值,若是停顿半秒就执行搜索,若是搜索了屡次,发起了屡次请求,那只返回最终输入的那次搜索结果。

闭上眼想一想,你以前是怎么实现的。反正我都是设置开始时间,结束时间,上次时间,等等变量。繁琐,并且不可控。

当咱们以FP的思想去实现时,就会千方百计的减小变量,来优雅程序。最多见的方法就是用下别人的工具库来实现它。固然有些简单的场景也能够本身实现,最主要的仍是要有这个意识。

其实咱们日常已经写了一些FP了,只是咱们没意识到,或者没怎么写好。就比如闭包,不少人都不了解闭包的概念,但实际上已经写了不少闭包代码。其实闭包自己也是函数式编程的一个应用。

鉴于我本身理解也不深,无法多阐述FP的应用,你们若是有兴趣,能够多了解了解。

FP在JavaScript中的优劣势

总结一下FP的优劣,以便于咱们在实际开发中,能更好的抉择是否采用FP。

优点

  1. 更好的管理状态。由于它的宗旨是无状态,或者说更少的状态。而日常DOM的开发中,由于DOM的视觉呈现依托于状态变化,因此不可避免的产生了很是多的状态,并且不一样组件可能还相互依赖。以FP来编程,能最大化的减小这些未知、优化代码、减小出错状况。

  2. 更简单的复用。极端的FP代码应该是每一行代码都是一个函数,固然咱们不须要这么极端。咱们尽可能的把过程逻辑以更纯的函数来实现,固定输入->固定输出,没有其余外部变量影响,而且无反作用。这样代码复用时,彻底不须要考虑它的内部实现和外部影响。

  3. 更优雅的组合。往大的说,网页是由各个组件组成的。往小的说,一个函数也多是由多个小函数组成的。参考上面第二点,更强的复用性,带来更强大的组合性。

  4. 隐性好处。减小代码量,提升维护性。

劣势

  1. JavaScript不能算是严格意义上的函数式语言,不少函数式编程的特性并无。好比上文说的数组的惰性链求值。为了实现它就得上工具库,或者本身封装实现,提升了代码编写成本。

  2. 跟过程式相比,它并无提升性能。有些地方,若是强制用FP去写,因为没有中间变量,还可能会下降性能。

  3. 代码不易读。这个因人而异,因码而已。特别熟悉FP的人可能会以为这段代码一目了然。而不熟悉的人,遇到写的晦涩的代码,看着一堆堆lambda演算跟匿名函数 () => () => () 瞬间就懵逼了。看懂代码,得脑子里先演算半小时。

  4. 学习成本高。一方面继承于上一点。另外一方面,不少前端coder,就是由于相对不喜欢一些底层的抽象的编程语言,才来踏入前端坑,你如今又让他们一头扎入FP,显得手足无措。

总结

我的以为,FP仍是好的。对于开发而言,确确实实能优化咱们的代码,熟悉以后,也能提升编程效率。对于编程自己而言,也能拓展咱们的思惟,不局限在过程式的编程代码。

在编写JS中,能够尽可能的运用FP的思惟,如不可变量、纯函数、惰性求值。但也没必要教条式的遵循函数式编程,必定要怎样怎样。好比咱们看下知乎大V某温的一个回答:传送门

唉,作个页面仔不容易啊。可是不想当大牛的页面仔不是好页面仔!

参考

  1. 函数式编程入门教程-阮一峰

  2. 函数编程语言-维基百科

  3. 前端开发js函数式编程真实用途体如今哪里?-知乎答者

相关文章
相关标签/搜索