什么是JavaScript函数式编程?传统老爷子拿起JQuery,应付现在繁重的交互页面已经很累了。于是就有了Angular、React、Vue等现代框架。但是随之而来的新知识新名词也很多,比如MVC、MVVM、Flux等设计模式,让很多同学一头雾水。这个时候看到别人在讨论函数式编程,我就更加懵了。我们大多数人都听说过面向对象编程和面向过程编程,那么什么是函数式编程呢?我们前端开发有哪些应用场景?带着这个疑问,我做了一些初步的研究。(本文仅供学习,干货不多)。函数式编程定义了函数式编程(FunctionalProgramming,以下简称FP),维基百科的定义是:一种将计算机操作视为数学函数计算,并避免使用程序状态和变量对象的编程范式。函数式编程语言最重要的基础是lambda演算。并且lambda演算的函数可以接受函数作为输入(参数)和输出(传出值)。与命令式编程相比,函数式编程更强调程序执行的结果,而不是执行过程。它提倡用几个简单的执行单元,使计算结果递进,逐层推导复杂的运算,而不是设计一个复杂的执行过程。让我试着理解这个定义。好像是说在敲代码的时候,我应该把流程逻辑写成一个函数,定义入参,只关心它的输出。函数可以用作输入和输出。感觉平时写js就是这个样子!特色网站上关于FP的定义和特点让人眼花缭乱。各种百科全书,博客,还有一些老师的网站都有类似的介绍。为了阅读方便,我列出几个看似比较重要的特性,附上我的初步理解。函数是一等公民。也就是说,函数可以像其他变量一样作为其他函数的输入和输出。哦,回调函数就是典型的应用。不可变的。也就是说不能用var和let。按照这个要求,我写代码好像有点吃力。纯函数。这是一个没有副作用的功能。这个很好理解,就是不修改函数外的变量。参照透明。这个也很好理解,就是说相同的输入一定是相同的输出。函数内部不依赖于外部状态,比如一些全局变量。懒惰的计算。大意是:一个被表达式绑定的变量,在声明的时候不计算,而是在实际使用的时候计算。还有一些衍生的特性,比如currying和combination,不是三言两语能说清楚的,就不细说了。有兴趣的同学可以自行深入了解。FP在JavaScriptReact中的应用就是典型的FP。它不同于像Vue这样的MVVM框架,它只是一个View层。ReactView=render(data)它只关心你的输入,最后返回给你相应的视图。所以你不想在react组件中修改父组件的状态,也没有与dom的双向绑定。这是框架上的应用,那么我们平时写JavaScript的时候都有哪些应用呢?也就是说,我们平时写js的时候,不管什么情况,还是用FP比较好。先说最常见的,比如一个典型的数组操作://从users中过滤掉15岁以上的人的名字constusers=[{age:10,name:'张三',},{age:20,name:'李四'},{age:30,name:'王舞'}];//proceduralconstnames=[];for(leti=0;i15){names.push(users[i].name);}}//functionalconstnames=users.filter(u=>u.age>15).map(u=>u.name);嗯,代码已经简化了很多,但是似乎带来了更多的开销。如果是非常大的数据,筛选工作很多,会循环很多次。这里我们不得不想到刚才的惰性计算。按照lazyevaluation的要求,应该是在最终返回结果的时候,才真正筛选出age,得到name数组。但是,JavaScript数组不支持惰性求值。这时候我们就不得不用到一些工具库了,比如Lodash。您可以在其文档中看到一个示例:_.chain。好像也好不到哪里去,不就是把多行代码改成一行吗?好神秘啊,性能开销也比较多,到时候可以和我说一个工具库。..说的好像有道理,但是for循环有个缺点。它产生一个变量i,这个变量是不可控的。如果业务逻辑复杂,谁知道什么时候循环,i有没有变。那么是什么原因导致循环出错呢?再来看另一个与DOM交互的场景:如果页面有一个button按钮,我们需要找出用户点击了多少次,但是一秒内重复点击不算。传统的方法会这样写。varcount=0;varrate=1000;varlastClick=Date.now()-rate;varbutton=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中引用的,我们来看看它是如何优雅处理的。varbutton=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的应用。如果你有兴趣,你可以了解更多。JavaScript中FP的优缺点总结一下FP的优缺点,以便我们在实际开发中更好的决定是否使用FP。优点更好的管理状态。因为它的目的是无状态的,或者说是无状态的。在正常的DOM开发中,由于DOM的视觉呈现依赖于状态的变化,因此不可避免地会产生很多状态,不同的组件之间可能会相互依赖。使用FP编程可以最大限度地减少这些未知数、优化代码并减少错误。更容易重用。极端的FP代码应该是每一行代码都是一个函数,当然我们不需要那么极端。我们尽量用更纯粹的函数实现流程逻辑,固定输入->固定输出,不受其他外部变量的影响,无副作用。这样,在复用代码时,就无需考虑其内部实现和外部影响。更优雅的组合。从广义上讲,网页由各种组件组成。在更小的尺度上,一个函数也可能由多个小函数组成。参考上面第二点,更强的复用性带来更强大的组合。隐藏的好处。减少代码量,提高可维护性。缺点JavaScript不能算是严格意义上的函数式语言,很多函数式编程的特性是不具备的。比如上面提到的数组的懒链求值。为了实现它,你必须使用工具库,或者自己封装它,这增加了编码成本。与程序相比,它不会提高性能。有的地方如果强行用FP写,因为没有中间变量,性能也可能会降低。代码不容易阅读。这因人而异,因代码而异。特别熟悉FP的人可能会发现这段代码一目了然。不熟悉的人遇到晦涩难懂的代码,看着一堆堆lambda演算和匿名函数()=>()=>()就会一头雾水。要看懂代码,得在脑子里算半个小时。学习成本很高。一方面它继承了前一点。另一方面,很多前端码农因为不喜欢一些低级抽象的编程语言而踏入前端坑。现在你让他们再一头扎进FP,他们就显得手足无措了。综上所述,我个人认为FP还是不错的。对于开发来说,确实可以优化我们的代码,熟悉之后,还可以提高编程效率。对于编程本身来说,也可以拓展我们的思路,不局限于过程式编程代码。在写JS的时候,尽量使用FP思维,比如不可变变量、纯函数、惰性求值等。但是没有必要教条地遵循函数式编程,你必须做一些事情。比如我们看文知乎这个大V的回答:传送门。唉,当个侍童可不容易啊。但是不想当大牛的男孩子就不是好男孩子!参考函数式编程入门教程-阮一峰函数式编程语言-维基百科前端开发JS函数式编程真正的用处在哪里?-知乎答题者