chaussen

Javascript与函数式编程(Functional Programming):简介

原文链接: hackernoon.com

Javascript与函数式编程(Functional Programming):简介

注:本文是“Javascript与函数式编程(Functional Programming)”系列的一部分。此系列是关于学习ES6版及以上版本的JavaScript中函数式的编程技术。这里可以找到第一等级的函数。

我总是很接近底线,对那些伪知识分子提出的概念,那些花哨的术语和天花乱坠的宣传毫不感兴趣,而那些能帮我尽快完工的工具与技术总是会拿来就用。这种做法一开始让我工作更高效,在创建用于“概念证明”的小型程序时尤其如此。

可惜工作范围不同,这种做法就不行了。我作为一个开发人员,随着个人的发展,感到自己的生产效率开始有一种收益递减规律了。我能很快地设立一个项目并达成基本功能,但程序越来越复杂,也开始发生一些严重的问题。要让一个项目在周期内向前发展,我写的代码也会变得复杂。之前写过的代码变得很难分析,必须极其地集中精神才能理解代码。

我一直有种迫切的感觉,希望存在更完善更简洁的软件开发方法。我听说过一些关于函数式编程的传言,还听说过这个方法如何让开发人员能写出更精确更优美的代码。在我使用React框架和Redux库时,已经第一次接触到了这种功能性编程模式,只是自己不知道。这种模式的原则已经整合入了React框架和Redux库,我很喜欢。我看了一些关于函数式编程(FP)的文章,第一反应却是忧虑,因为我看到这个模式的基础是抽象数学概念,在学术界很流行。我的目标是尽快地完工,所以直觉上感到这种方法似乎与我想做背道而驰。在工程学校读了四年书,我形成了一个观念,那就是学术界只会处理理论性的问题,不太可能对我日常创作还会有什么帮助。

????????????????????????????????

但我却摆脱不了函数式编程(FP),因为我最喜欢的开源软件、博客贴子和教程中都有其存在,网上到处都散布着那种优美的解法和模式。我放下心中的疑虑,开始深入研究函数式编程(FP)。

就让我们做一做这个叫函数式编程(FP)的玩意儿吧!

虽然这里的概念牵涉到一些新的术语,而且学习过程要求很高,但我对这种“新方法”感到非常惊奇兴奋。在这一系列文章里,我要分享一下我的学习体会,目标是将函数式编程(FP)的精妙之处提炼并总结出来,使大家在开发过程中感觉工作更简洁更精确。我会试着让讨论的模式理解起来更直观,问题与解法表达得尽可能简单,并跳过一些过于复杂的定义。很多人说学习函数式编程(FP)有点让人望而却步,但如果把这些概念打散成更小的知识块,我们就能更容易地消化。

选自精彩的《函数式编程差强人意指南》(Mostly Adequate FP Guide)

函数式编程(FP)与其它编程模式最主要的区别在于函数式编程(FP)用声明式(declarative)方法,而不是命令式(imperative)。我们先看一个例子,了解一下几个区别,然后才开始研究正式的定义。

命令式(Imperative)

// 给定数组中每个元素扩大到三倍值
const triple = (arr) => {
  let results = []
  for (let i = 0; i < arr.length; i++){
    results.push(arr[i] * 3)
  }
  return results
}

// 给定数组中所有元素求和
const sum = (arr) => {
  let result = 0
  for (let i = 0; i < arr.length; i++){
    result += arr[i]
  }
  return result
}

自然界中的命令式函数

这段代码看起来是不是很不舒服?应该是的!那上面的两个方法之间有什么相似之处?

  1. 代码片段一主要复杂在这一点上:它在指导电脑如何做,而不是告诉电脑 我们要什么what we want。代码告诉电脑如何操作,比如找到数组中索引数为i的元素,然后修改或交换值,那就叫命令式代码。

  2. 这段代码很难懂(???)。这只是个小小的例子,但程序越来越大,功能变得越来越复杂,像这样用for循环语句写代码不是简单的事,大脑需要分析循环内部的运作,同时还要追踪索引数,变量等等。命令式代码增加了阅读时的认知负荷,时间长更容易在代码分析与代码逻辑方面出问题。

声明式(Declarative)

让我们重新把这段代码写一遍,不过这次用的是声明方式。

// 给定数组中每个元素扩大到三倍值
const triple = (arr) => arr.map((currentItem) => currentItem * 3)

// 给定数组中所有元素求和
const sum = (arr) => arr.reduce((prev, current) => prev + current, 0)

.map函数?.reduce函数?什么鬼?

首先一点,我保证只要输入数据相同,这两个方法输出的结果每一次都会是一样的。

关于声明式代码,这里快速插播一下:

**.map()**映射函数是JavaScript里的一个方法,通过每个数组都可以调用。一个数组调用**.map()**函数,就会在其每个元素上都调用给定的函数,所有得出的结果组成一个新数组返回。

**.reduce()**归纳函数可以根据累加器和数组每个元素运行给定的函数,从左到右将这个数组还原成一个单一的值。

现在还不用为这些苦恼。这些原生的数组方法很有用,我们会在后面的贴子里深入了解。不过有一点很清楚,声明式代码段比命令式更精确,也好读得多。只要给**.map()**函数和** .reduce()**函数提供一个表达式,告诉程序我要的是什么就行了。我们这个例子里表达式是一个无名函数,表示每个元素都要这么处理,而不是指导程序要去找哪个索引数的元素等。

这种声明式方法能全面充分地满足我们的需求,有以下两个原因:

  1. 我们在代码中学用这些模式很多人都明白,很容易读懂,_并且_人们已经证实用这些模式就不会有让代码看不懂的错误了。

  2. 代码组成得更短,表达得更清晰更精确。毕竟,写的代码越少,调试的内容也越少。

最重要的一点是,这些工具和模式有助于我(们)实现最终目标:更快发货。请看下一贴,我们要讨论一下JavaScript里的函数,看看函数的特别之处,还有其特征如何能使函数式编程(FP)可行。

如果本贴有帮助,请点击下方鼓掌按钮以示支持!⬇⬇

LinkedinMedium上关注我。

最重要的事!我在Mindflow.ai.上写了这些教程。Mindflow会自动为工作流程创建智能总结(差不多)。有了这个,我的工作文档易如反掌!注册可使用alpha版本.