"close-up photo of factory" by Taton Moïse on Unsplash

原文链接 By: Krzysztof Czernek

这是 "函数式 JS" 系列的第二篇。查看第一篇

简介

现在我们知道为什么学习函数式编程实践可以帮助你成为一个更好的程序员了,那让我们开始一些有趣的东西吧。

在这一部分中,我们将重点关注与函数式编程相关的术语基本概念

遗憾的是,这次不会涉及很多代码。从好的方面来说,一旦我们理解了术语,我们就能够方便地讨论更复杂的主题。


函数

毋庸置疑,函数式编程中最重要的就是函数。

我们都知道什么是函数。它基本上就是一个(大多数时候都会有一个名字的)代码片段。

function add (x, y) {return x + y
}
复制代码

然而,当谈到函数式编程时,我们更想从一个特殊的角度来看待函数:数学中的函数。

数学?没搞错吧...

即使我们不必真的去使用代数,我们也不得不承认函数式编程深深植根于数学。

在简单的数学术语中,函数是一种在给定输入的情况下产生特定输出的机器

有趣的是,给定输入只能有一个输出。这意味着,如果我们为函数提供相同的输入,我们希望它始终做同样的事情,并且返回相同的值

这听起来没什么大不了,但实际上这是一个很强的限制。这个数学定义有着深远的影响:

  • 除了输入(参数)之外,函数不能有其他任何依赖
  • 函数必须返回单个值
  • 函数必须是确定性的(不能使用随机值等)

满足这些标准的函数在编程中称为纯函数,它们对于函数式范式至关重要。

纯函数

让我们看一下 JavaScript 中的一些函数示例,直接体会一下什么是纯函数。

function coin () {return Math.random() < 0.5 ? 'heads' : 'tails'
}
复制代码

Coin 不是纯函数,因为它在给定相同输入(null)的情况下并不总是产生相同的结果 - 它不是确定性的。

let firstName = 'krzysztof'function uppercaseName (lastName) {return `${firstName.toUpperCase()} ${lastName.toUpperCase()}`
}
复制代码

uppercaseName 不是纯函数,因为它依赖于一个不受其控制的变量。我们无法确定在给定相同参数的情况下它总会产生相同的结果。

let user = {firstName: 'Krzysztof',age: '26'
}function happyBirthday () {user.age = user.age + 1
}
复制代码

happyBirthday不是纯函数,因为它不仅访问了一个不受控制的变量,还不会返回任何内容。

function calculatePrice (unitPrice, noOfUnits, couponValue = 0) {return unitPrice * noOfUnits - couponValue;
}
复制代码

calculatePrice是纯函数。它不使用任何超出其控制范围的变量,它是确定性的,我们可以非常有信心地说它将始终为相同的输入参数组合返回相同的结果。

然后呢?

为什么这一切很重要?有以下一些原因表明纯函数比非纯函数更有优势:

  1. 更易阅读

你只需要读一下它的函数体就知道它做了哪些事情。

  1. 更易理解

不需要查找外部依赖,函数被调用的上下文等。这些对于纯函数都没有任何影响。

  1. 更易测试

如果你想测试一个纯函数,你只需要用一些参数调用它,看看结果是否是你想要的结果。根本无需复杂的设置。

  1. 更高效

如果我们知道对于给定的输入,函数将始终产生相同的输出,我们就可以缓存(memoize)它的结果,这样我们就不必在每次调用这个函数的时候都重新计算它。

使用纯函数可以使代码更易于维护 - 因为它可以更轻松地管理副作用。在接下来的部分中,我们将了解副作用是什么以及为什么,遗憾的是,计算机程序中不可能全部都是纯函数。

现在我们知道了什么是纯函数,让我们关注下一个与函数相关的术语:作为一等公民的函数

一等公民函数

与“纯函数”不同,“一等公民函数”在日常工作中并不是一个很实用的概念。但是,在考虑编程语言的特性时,它就很有用了。

如果在一个编程语言中,函数可以像使用其他的值同样的方式使用,那么你就可以说这个语言具有“一等公民的函数”,也就是说:

  1. 它们可以被传递,
  2. 它们可以被分配给变量,
  3. 它们可以被存储在更复杂的数据结构中,如数组或对象。

可以说没有一等公民的函数,就没有函数式编程(至少会非常的尴尬)。下面这个例子,说明为什么函数在 JavaScript 中是一等公民:

function add (a, b) {return a + b
}function multiply (a, b) {return a * b
}const operations = { // 这里我们把函数当成普通的值使用add,multiply
}operations.add(1, 2)
复制代码

正如上面所说,JavaScript 的函数可以在不同的函数之间传递。但是......这么做的目的是什么呢?

嗯,将函数传入和传出到另外一个函数是函数式编程中的常见做法 - 而且功能非常强大。它给我们引入了...

高阶函数

可以“操作”其他函数的函数被称为高阶函数。这里的操作,意思是指他们可以做到下面两点中的一个或两个:

  • 把其他函数作为参数,
  • 返回一个函数。

这个例子在 JavaScript 世界中很常见。其中一个示例是标准库中的 Array.prototype.map 函数。它需要一个函数作为参数并将其应用于数组中的每个元素:

const numbers = [1, 1, 2, 3, 5, 8]
const transformFunction = x => x + 2numbers.map(transformFunction)
复制代码

下面是一个返回函数的函数,这个示例稍显刻意:

function makeGreeter (greeting) {return function greet (name) {return `${greeting}, ${name}!`}
}// 或者使用 ES6 的语法:const makeGreeter = greeting => name => `${greeting}, ${name}!`const greet = makeGreeter('Hello')
console.log(greet('Krzysztof'))
复制代码

你可以看到,这些函数(map 和 makeGreeter)不接受或者返回我们所知道的那些常规的值。他们在操作函数。

你可能已经熟悉了一些高阶函数,例如:

  • map,
  • reduce,
  • filter,
  • compose,
  • forEach,
  • … 和别的。

函数式编程就是将一些小型,可重用和通用的函数组合成更复杂的函数。因此,在后面的讨论中你将会看到更多不同的高阶函数。


那么,这就是我们开始 FP 之旅所需的所有与函数相关的基本术语了。

下一章,我们将关注函数式编程中的状态 (state) - 如何管理它,以及如何避免它带来的问题等等。我们已经提到过一些关于状态的内容(在讨论纯函数的时候),后面还有更多!

我们已经学到了不少东西,希望你和我一样对下一章感到兴奋!

(译) 函数式 JS #2: 函数!相关推荐

  1. [js] 纯函数和函数式编程有什么关系?

    [js] 纯函数和函数式编程有什么关系? 函数式编程是一种编程思想,纯函数是这种思想的基本要实现函数式编程,我们所封装的方法应该是抽象的,应该是和外部状态无关系的,也就需要是纯函数的,这样才能保证抽象 ...

  2. js用函数实现输出100以内与7有关的数_走近(javascript, 函数式)

    什么是函数式 目前主流的命令式编程方式当中,将程序抽象成数据和过程的集合.在这里,"名词"是第一词汇,我们将程序视为一系列自上而下的命令,去不断修改其中的数据,我们更专注于描述不同 ...

  3. [译]函数式响应编程入门指南

    原文地址:An Introduction to Functional Reactive Programming 原文作者:Daniel Lew 译文出自:掘金翻译计划 本文永久链接:github.co ...

  4. js匿名函数--转了

    js匿名函数--转了 一.什么是匿名函数? 在Javascript定义一个函数一般有如下三种方式: 函数关键字(function )语句:function fnMethodName(x) {alert ...

  5. js中函数对象的方法,原型方法apply、call、bind、toString、toLocaleString、valueOf

    全栈工程师开发手册 (作者:栾鹏) js系列教程4-函数.函数参数教程全解 js中函数也是一种对象,因此有自己的原型对象,可以作为其他对象的属性,也可以作为其他函数的参数. 函数方法 [apply() ...

  6. 用于业务的精炼js工具函数(浏览器环境)

    js工具函数(浏览器环境) github : github.com/Javison666/- 引用库,后续 $fn 直接当作全局进行使用 import $fn from 'jj-browser-fn' ...

  7. js自定义函数及参数问题

    js自定义函数的过程中,往往我们希望指定一些参数的默认值 很容易的会写出如下的js 方法 function test(a,b,c=1,d='id'){ return 1; } 但是定义完之后,浏览器会 ...

  8. 【转】JS回调函数--简单易懂有实例

    JS回调函数--简单易懂有实例 初学js的时候,被回调函数搞得很晕,现在回过头来总结一下什么是回调函数. 我们先来看看回调的英文定义:A callback is a function that is ...

  9. url的三个js编码函数escape(),encodeURI(),encodeURIComponent()简介

    转载地址:http://www.haorooms.com/post/js_escape_encodeURIComponent 引子 浏览器URl地址,上网一定会用到,但是浏览器地址有中文或者浏览器ur ...

最新文章

  1. Docker 入门系列(6)- Docker 互联
  2. 唯品会HDFS性能挑战和优化实践
  3. 如何快速搭建一个简约美观的在线互动教室?
  4. 【Qt】Qt中JSON简介
  5. 3dmax导出x文件插件2020_C4D与unity3D,3DMAX,AI,AE,ks之间互导
  6. 虚拟机安装 xp步骤(参照百度文库)
  7. hive case when语法_SQL中CASE表达式的妙用
  8. matlab与vc混合编程指导书.doc,vc与matlab混合编程—基于com.doc
  9. H3C设备运行状态查询常用命令
  10. ios 仿微信,短信聊天气泡
  11. 《设计师要懂心理学》-第九章-人会犯错
  12. ArcGIS发布地图服务--ArcMap
  13. 结构体定义的几种方式
  14. juki贴片机是什么牌子,juki贴片机型号一览表
  15. win10电脑状态栏图标不见消失解决办法
  16. 考研英语语法_Day03_名词性从句
  17. 硬盘无法访问设备硬件出现致命错误,导致请求失败数据找到的法子
  18. 手机厂商“卷”到了手腕上
  19. 天平游码读数例题_天平游码怎么读数?
  20. 【Linux学习】信号——信号保存 | 信号处理 | 不可重入函数,volatile,SIGCHLD信号

热门文章

  1. AI 岗位年薪下降 8.9%,程序员越“老”越吃香,最新薪酬报告发布!
  2. 因融资失败,应用崩溃,3 名程序员被“祭天”!
  3. vuex基础到模块化
  4. 一个仿微信朋友圈的图片查看框架 - PhotoViewer
  5. Java基础学习总结(23)——GUI编程
  6. 程序员的视角:java GC
  7. 用户配置,用户组管理,用户管理
  8. Codeforces 448E Divisors
  9. mysql数据库开启慢查询日志
  10. Android ANR产生的原理和如何避免