This commit is contained in:
geekpi 2017-10-19 08:54:08 +08:00
commit ec4b80d52a
8 changed files with 349 additions and 181 deletions

View File

@ -1,17 +1,17 @@
Android 在物联网方面能否像在移动终端一样成功?
Android 在物联网方面能否像在移动终端一样成功?
============================================================
![](https://cdn-images-1.medium.com/max/1000/1*GF6e6Vd-22PViWT8EDpLNA.jpeg)
*Android Things 让 IoT 如虎添翼*
### 我 在Android Things 上的最初 24 小时
### 我在 Android Things 上的最初 24 小时
正当我在开发一个基于 Android 的运行在树莓派 3 的物联网商业项目时,一些令人惊喜的事情发生了。谷歌发布了[Android Things][1] 的第一个预览版本,他们的 SDK 专门(目前)针对 3 个 SBC单板计算机 - 树莓派 3、英特尔 Edison 和恩智浦 Pico。说我一直在挣扎似乎有些轻描淡写 - 没有成功的移植树莓派 Android 可以参照,我们在理想丰满,但是实践漏洞百出的内测版本上叫苦不迭。其中一个问题,同时也是不可原谅的问题是,它不支持触摸屏,甚至连 [Element14][2] 官方销售的也不支持。曾经我认为 Android 已经支持树莓派,更早时候 [commi tto AOSP project from Google][3] 提到过树莓派曾让所有人兴奋不已。所以当 2016 年 12 月 12 日谷歌发布 “Android Things” 其 SDK 的时候,我马上闭门谢客,全身心地去研究了……
正当我在开发一个基于 Android 的运行在树莓派 3 的物联网商业项目时,一些令人惊喜的事情发生了。谷歌发布了[Android Things][1] 的第一个预览版本,他们的 SDK 专门(目前)针对 3 个 SBC单板计算机 —— 树莓派 3、英特尔 Edison 和恩智浦 Pico。说我一直在挣扎似乎有些轻描淡写 —— 树莓派上甚至没有一个成功的 Android 移植版本,我们在理想丰满,但是实践漏洞百出的内测版本上叫苦不迭。其中一个问题,同时也是不可原谅的问题是,它不支持触摸屏,甚至连 [Element14][2] 官方销售的也不支持。曾经我认为 Android 已经支持树莓派,更早时候 “[谷歌向 AOSP 项目发起提交][3]” 中提到过树莓派曾让所有人兴奋不已。所以当 2016 年 12 月 12 日谷歌发布 “Android Things” 其 SDK 的时候,我马上闭门谢客,全身心地去研究了……
### 问题?
关于树莓派上的谷歌 Android 我遇到很多问题,我以前用 Android 做过许多开发,也做过一些树莓派项目,包括之前提到过的一个真正参与的。未来我会尝试解决它们,但是首先最重要的问题得到了解决 - 有完整的 Android Studio 支持,树莓派成为你手里的另一个常规的 ADB 可寻址设备。好极了。Android Studio 强大而便利、十分易用的功能包括布局预览、调试系统、源码检查器、自动化测试等都可以真正的应用在 IoT 硬件上。这些好处怎么说都不过分。到目前为止,我在树莓派上的大部分工作都是通过 SSH 使用运行在树莓派上的编辑器MC如果你真的想知道借助 Python 完成的。这是有效的,毫无疑问铁杆的 Pi/Python 粉丝或许会有更好的工作方式,而不是当前这种像极了 80 年代码农的软件开发模式。我的项目需要在控制树莓派的手机上编写 Android 软件,这真有点痛不欲生 - 我使用 Android Studio 做“真正的” Android 开发,借助 SSH 做剩下的。但是有了“Android Things”之后一切都结束了。
关于树莓派上的谷歌 Android 我遇到很多问题,我以前用 Android 做过许多开发,也做过一些树莓派项目,包括之前提到过的一个真正参与的。未来我会尝试解决这些问题,但是首先最重要的问题得到了解决 —— 有完整的 Android Studio 支持,树莓派成为你手里的另一个常规的 ADB 可寻址设备。好极了。Android Studio 强大而便利、十分易用的功能包括布局预览、调试系统、源码检查器、自动化测试等都可以真正的应用在 IoT 硬件上。这些好处怎么说都不过分。到目前为止,我在树莓派上的大部分工作都是通过 SSH 使用运行在树莓派上的编辑器MC如果你真的想知道借助 Python 完成的。这是有效的,毫无疑问铁杆的 Pi/Python 粉丝或许会有更好的工作方式,而不是当前这种像极了 80 年代码农的软件开发模式。我的项目需要在控制树莓派的手机上编写 Android 软件,这真有点痛不欲生 —— 我使用 Android Studio 做“真正的” Android 开发,借助 SSH 做剩下的。但是有了“Android Things”之后一切都结束了。
所有的示例代码都适用于这三种 SBC树莓派只是其中之一。 `Build.DEVICE` 常量可以在运行时确定是哪一个,所以你会看到很多如下代码:
@ -32,7 +32,7 @@
}
```
我对 GPIO 处理有浓厚的兴趣。 由于我只熟悉树莓派,我只能假定其 SBC 工作方式相同GPIO 只是一组引脚,可以定义为输入/输出,是连接物理外部世界的主要接口。 基于 Linux 的树莓派操作系统通过 Python 中的读取和写入方法提供了完整和便捷的支持,但对于 Android您必须使用 NDK 编写 C++ 驱动程序,并通过 JNI 在 Java 中与这些驱动程序对接。 不是那么困难,但需要在你的构建链中维护额外的一些东西。 树莓派还为 I2C 指定了 2 个引脚时钟和数据因此需要额外的工作来处理它们。I2C 是真正酷的总线寻址系统,它通过串行化将许多独立的数据引脚转换成一个。 所以这里的优势是 - Android Things 已经帮你完成了所有这一切。 你只需要 `read()``write() ` 你需要的任何 GPIO 引脚I2C 同样容易:
我对 GPIO 处理有浓厚的兴趣。 由于我只熟悉树莓派,我只能假定其 SBC 工作方式相同GPIO 只是一组引脚,可以定义为输入/输出,是连接物理外部世界的主要接口。 基于 Linux 的树莓派操作系统通过 Python 中的读取和写入方法提供了完整和便捷的支持,但对于 Android您必须使用 NDK 编写 C++ 驱动程序,并通过 JNI 在 Java 中与这些驱动程序对接。 不是那么困难,但需要在你的构建链中维护额外的一些东西。 树莓派还为 I2C 指定了 2 个引脚时钟和数据因此需要额外的工作来处理它们。I2C 是真正酷的总线寻址系统,它通过串行化将许多独立的数据引脚转换成一个。 所以这里的优势是 —— Android Things 已经帮你完成了所有这一切。 你只需要 `read()``write() ` 你需要的任何 GPIO 引脚I2C 同样容易:
```
public class HomeActivity extends Activity {
@ -73,11 +73,11 @@ public class HomeActivity extends Activity {
### Android Things 基于 Android 的哪个版本?
看起来是 Android 7.0,这样很好,因为我们可以继承 Android 所有以前版本的平板设计 UI、优化安全加固等。它也带来了一个有趣的问题 - 与应用程序必须单独管理不同,未来的平台应如何更新升级?请记住,这些设备可能无法连接到互联网。我们可能不便于连接蜂窝/ WiFi ,即便之前这些连接能用,但是有时不那么可靠。
看起来是 Android 7.0,这样很好,因为我们可以继承 Android 所有以前版本的平板设计 UI、优化安全加固等。它也带来了一个有趣的问题 —— 与应用程序必须单独管理不同,未来的平台应如何更新升级?请记住,这些设备可能无法连接到互联网。我们可能不便于连接蜂窝 / WiFi ,即便之前这些连接能用,但是有时不那么可靠。
另一个担心是Android Things 仅仅是一个名字不同的 Android 分支版本,大部分都是一样的,和已经发布的 Arduino 一样,更像为了市场营销而出现,而不是作为操作系统。不过可以放心,实际上通过[样例][4]可以看到,其中一些样例甚至使用了 SVG 图形作为资源,而不是传统的基于位图的图形(当然也能轻松处理) ——这是一个非常新的 Android 创新。
另一个担心是Android Things 仅仅是一个名字不同的 Android 分支版本,大部分都是一样的,和已经发布的 Arduino 一样,更像为了市场营销而出现,而不是作为操作系统。不过可以放心,实际上通过[样例][4]可以看到,其中一些样例甚至使用了 SVG 图形作为资源,而不是传统的基于位图的图形(当然也能轻松处理) —— 这是一个非常新的 Android 创新。
不可避免地,与 Android Things 相比,普通的 Android 会有些不同。例如,权限问题。因为 Android Things 为固定硬件设计,在构建好之后,用户通常不会在这种设备上安装应用,所以在一定程序上减轻了这个问题,尽管当设备要求权限时是个问题——因为它们没有 UI。解决方案是当应用在安装时给予所有需要的权限。 通常,这些设备只有一个应用,并且该应用从设备上电的那一刻就开始运行。
不可避免地,与 Android Things 相比,普通的 Android 会有些不同。例如,权限问题。因为 Android Things 为固定硬件设计,在构建好之后,用户通常不会在这种设备上安装应用,所以在一定程序上减轻了这个问题,尽管当设备要求权限时是个问题 —— 因为它们没有 UI。解决方案是当应用在安装时给予所有需要的权限。 通常,这些设备只有一个应用,并且该应用从设备上电的那一刻就开始运行。
![](https://cdn-images-1.medium.com/max/800/1*pi7HyLT-BVwHQ_Rw3TDSWQ.png)
@ -87,35 +87,35 @@ Brillo 是谷歌以前的 IoT 操作系统的代号,听起来很像 Android Th
### UI 指南?
谷歌针对 Android 智能手机和平板电脑应用发布了大量指南,例如屏幕按钮间距等。 当然,你最好在可行的情况下遵循这些,但这已经不是本文应该考虑的范畴了。 缺省情况下什么也没有 - 应用程序作者决定一切,这包括顶部状态栏,底部导航栏 - 绝对是一切。 多年来谷歌一直在告诉 Android 应用程序的作者们绝不要在屏幕上放置返回按钮,因为平台将提供一个,因为 Android Things [可能甚至没有 UI] [5]
谷歌针对 Android 智能手机和平板电脑应用发布了大量指南,例如屏幕按钮间距等。 当然,你最好在可行的情况下遵循这些,但这已经不是本文应该考虑的范畴了。 缺省情况下什么也没有 —— 应用程序作者决定一切,这包括顶部状态栏,底部导航栏 —— 绝对是一切。 多年来谷歌一直在告诉 Android 应用程序的作者们绝不要在屏幕上放置返回按钮,因为平台将提供一个,因为 Android Things [可能甚至没有 UI][5]
### 智能手机上会有多少谷歌服务?
有一些但不是所有。第一个预览版本没有蓝牙支持、没有NFC这两者都对物联网革命有重大贡献。 SBC 支持它们,所以我们应该不会等待太久。由于没有通知栏,因此不支持任何通知。没有地图。缺省没有软键盘,你必须自己安装一个键盘。由于没有 Play 商店,你只能难地通过 ADB 做这个和许多其他操作。
有一些,但不是所有。第一个预览版本没有蓝牙支持、没有 NFC这两者都对物联网革命有重大贡献。 SBC 支持它们,所以我们应该不会等待太久。由于没有通知栏,因此不支持任何通知。没有地图。缺省没有软键盘,你必须自己安装一个键盘。由于没有 Play 商店,你只能难地通过 ADB 做这个和许多其他操作。
当为 Android Things 开发时,我试图为运行在手机上和树莓派上使用同一个 APK。这引发了一个错误阻止它安装在除 Android Things 设备之外的任何设备:`com.google.android.things` 不存在。 这有点用,因为只有 Android Things 设备需要这个,但它似乎是个限制,因为不仅智能手机或平板电脑上没有,连模拟器上也没有。似乎只能在物理 Android Things 设备上运行和测试您的 Android Things 应用程序……直到谷歌在 [G+ 谷歌的 IoT 开发人员社区][6]组中回答了我的问题,并提供了规避方案。但是,躲过初一,躲不过十五。
当为 Android Things 开发时,我试图为运行在手机上和树莓派上使用同一个 APK。这引发了一个错误阻止它安装在除 Android Things 设备之外的任何设备:`com.google.android.things` 不存在。 这有点用,因为只有 Android Things 设备需要这个,但它似乎是个限制,因为不仅智能手机或平板电脑上没有,连模拟器上也没有。似乎只能在物理 Android Things 设备上运行和测试您的 Android Things 应用程序……直到谷歌在 [G+ 谷歌的 IoT 开发人员社区][6]组中回答了我的问题,并提供了规避方案。但是,躲过初一,躲不过十五。
### 可以期待 Android Thing 生态演进到什么程度?
我期望看到移植更多传统的基于 Linux 服务器的应用程序,将 Android 限制在智能手机和平板电脑上没有意义。例如Web 服务器突然变得非常有用。已经有一些了,但没有像重量级的 Apache 或 Nginx。物联网设备可以没有本地 UI但通过浏览器管理它们当然是可行的因此需要用这种方式呈现 Web 面板。类似的那些如雷贯耳的通讯应用程序 - 它需要的仅是一个麦克风和扬声器,而且在理论上任何视频通话应用程序,如 Duo、Skype、FB 等都可行。这个演变能走多远目前只能猜测。会有 Play 商店吗?它们会展示广告吗?我们能够确保它们不会窥探我们,或被黑客控制它们么?从消费者的角度来看,物联网应该是具有触摸屏的网络连接设备,因为每个人都已经习惯于通过智能手机工作。
我期望看到移植更多传统的基于 Linux 服务器的应用程序,将 Android 限制在智能手机和平板电脑上没有意义。例如Web 服务器突然变得非常有用。已经有一些了,但没有像重量级的 Apache 或 Nginx。物联网设备可以没有本地 UI但通过浏览器管理它们当然是可行的因此需要用这种方式呈现 Web 面板。类似的那些如雷贯耳的通讯应用程序 —— 它需要的仅是一个麦克风和扬声器,而且在理论上任何视频通话应用程序,如 Duo、Skype、FB 等都可行。这个演变能走多远目前只能猜测。会有 Play 商店吗?它们会展示广告吗?我们能够确保它们不会窥探我们,或被黑客控制它们么?从消费者的角度来看,物联网应该是具有触摸屏的网络连接设备,因为每个人都已经习惯于通过智能手机工作。
我还期望看到硬件的迅速发展 - 特别是有更多的 SBC 拥有更低的成本。看看惊人的 5 美元 树莓派 Zero不幸的是由于其有限的 CPU 和内存,几乎可以肯定不能运行 Android Things。多久之后像这样的设备才能运行 Android Things这是很明显的标杆已经设定任何有追求的 SBC 制造商将瞄准 Android Things 的兼容性,规模经济也将波及到外围设备,如 23 美元的触摸屏。没人会购买不会播放 YouTube 的微波炉,你的洗碗机会在 eBay 上购买更多的清洁粉,因为它注意到你很少使用它……
我还期望看到硬件的迅速发展 —— 特别是有更多的 SBC 拥有更低的成本。看看惊人的 5 美元树莓派 Zero不幸的是由于其有限的 CPU 和内存,几乎可以肯定不能运行 Android Things。多久之后像这样的设备才能运行 Android Things这是很明显的标杆已经设定任何有追求的 SBC 制造商将瞄准 Android Things 的兼容性,规模经济也将波及到外围设备,如 23 美元的触摸屏。没人会购买不会播放 YouTube 的微波炉,你的洗碗机会在 eBay 上购买更多的清洁粉,因为它注意到你很少使用它……
然而,我不认为我们会过于冲昏头脑。了解一点 Android 架构有助于将其视为一个包罗万象的物联网操作系统。它仍然使用 Java其垃圾回收机制导致的所有时序问题在过去几乎把它搞死。这仅仅是问题最少的部分。真正的实时操作系统依赖于可预测、准确和坚如磐石的时序或者它不能被用于“关键任务”。想想医疗应用、安全监视器,工业控制器等。使用 Android如果宿主操作系统认为它需要理论上可以在任何时候杀死您的活动/服务。这在手机上没那么糟糕 - 用户可以重新启动应用程序,杀死其他应用程序,或重新启动手机。但心脏监视器就完全是另一码事。如果前台的活动/服务正在监视一个 GPIO 引脚,而这个信号没有被准确地处理,我们就完了。必须要做一些相当根本的改变让 Android 来支持这一点,到目前为止还没有迹象表明它已经在计划之中了。
然而,我不认为我们会过于冲昏头脑。了解一点 Android 架构有助于将其视为一个包罗万象的物联网操作系统。它仍然使用 Java其垃圾回收机制导致的所有时序问题在过去几乎把它搞死。这仅仅是问题最少的部分。真正的实时操作系统依赖于可预测、准确和坚如磐石的时序要么它就不能被用于“关键任务”。想想医疗应用、安全监视器,工业控制器等。使用 Android如果宿主操作系统认为它需要理论上可以在任何时候杀死您的活动/服务。这在手机上没那么糟糕 —— 用户可以重新启动应用程序,杀死其他应用程序,或重新启动手机。但心脏监视器就完全是另一码事。如果前台的活动/服务正在监视一个 GPIO 引脚,而这个信号没有被准确地处理,我们就完了。必须要做一些相当根本的改变让 Android 来支持这一点,到目前为止还没有迹象表明它已经在计划之中了。
###这 24 小时
### 这 24 小时
所以,回到我的项目。 我认为我会接管我已经完成和尽力能为的工作,等待不可避免的路障,并向 G+ 社区寻求帮助。 除了一些在非 Android Things 设备上如何运行程序的问题之外,没有其他问题。 它运行得很好! 这个项目也使用了一些奇怪的东西,如自定义字体、高精定时器 - 所有这些都在 Android Studio 中完美地展现。对我而言,可以打满分 - 至少我能够开始做出实际原型,而不只是视频和截图。
所以,回到我的项目。 我认为我会接管我已经完成和尽力能为的工作,等待不可避免的路障,并向 G+ 社区寻求帮助。 除了一些在非 Android Things 设备上如何运行程序的问题之外,没有其他问题。它运行得很好! 这个项目也使用了一些奇怪的东西,如自定义字体、高精定时器 —— 所有这些都在 Android Studio 中完美地展现。对我而言,可以打满分 —— 至少我能够开始做出实际原型,而不只是视频和截图。
### 蓝图
今天的物联网操作系统环境看起来非常零碎。 显然没有市场领导者,尽管炒作之声沸反连天,物联网仍然在草创阶段。 谷歌 Android 物联网能否像它在移动端那样取得成功?现在 Android 在移动方面的主导地位非常接近 90。我相信如果真的如此Android Things 的推出正是重要的一步。
今天的物联网操作系统环境看起来非常零碎。 显然没有市场领导者,尽管炒作之声沸反连天,物联网仍然在草创阶段。 谷歌 Android 物联网能否像它在移动端那样取得成功?现在 Android 在移动方面的主导地位几近达到 90。我相信如果真的如此Android Things 的推出正是重要的一步。
记住所有的关于开放和封闭软件的战争,它们主要发生在从不授权的苹果和一直担心免费还不够充分的谷歌之间。那个老梗又来了,因为让苹果推出一个免费的物联网操作系统的构想就像让他们免费赠送下一代 iPhone 一样遥不可及。
物联网操作系统游戏是开放的,大家机遇共享,不过这个时候,封闭派甚至不会公布它们的开发工具箱……
转到 [Developer Preview][7]网站,立即获取 Android Things SDK 的副本。
前往 [Developer Preview][7]网站,立即获取 Android Things SDK 的副本。
--------------------------------------------------------------------------------

View File

@ -1,14 +1,13 @@
### 密码修改最佳实践
密码修改最佳实践
=============
NIST 最近发表了四卷[ _SP800-63b 数字身份指南_][3]。除此之外,它还对密码提供三个重要的建议:
NIST 最近发表了四卷 [SP800-63b 数字身份指南][3]。除此之外,它还对密码提供三个重要的建议:
1. 不要再纠结于复杂的密码规则。它们使密码难以记住。因为人为的复杂密码很难输入,因此增加了错误。它们[也没有很大帮助][1]。最好让人们使用密码短语
1. 不要再纠结于复杂的密码规则。它们使密码难以记住。因为人为的复杂密码很难输入,因此增加了错误。它们[也没有很大帮助][1]。最好让人们使用密码短语。
2. 停止密码到期。这是[我们以前使用计算机的一个老的想法][2]。如今不要让人改变密码,除非有泄密的迹象。
3. 让人们使用密码管理器。这就是处理我们所有密码的方式。
2. 停止密码到期。这是[我们以前使用计算机的一个老的想法][2]。如今不要让人改变密码,除非有提示。
3. 让人们使用密码管理器。这是我们如何处理我们所需要的所有密码。
这些密码规则不能[让用户安全][4]。我们最好修复系统安全。
这些密码规则不能[让用户安全][4]。让系统安全才是最重要的。
--------------------------------------------------------------------------------
@ -22,7 +21,7 @@ via: https://www.schneier.com/blog/archives/2017/10/changes_in_pass.html
作者:[Bruce Schneier][a]
译者:[geekpi](https://github.com/geekpi)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -1,39 +1,35 @@
让我们和 NixOS Linux 一起在安装前配置 OS
NixOS Linux 先配置后安装的 Linux
============================================================
![NixOS](https://www.linux.com/sites/lcom/files/styles/rendered_file/public/configuration.jpg?itok=IjKuFz05 "NixOS")
配置是成功安装 NixOS 的关键。[Creative Commons Zero][4]Pixabay
配置是成功安装 NixOS 的关键。
我用 Linux 有些年头了。在这些年里我很有幸见证了开源的发展。各色各样的发行版在安装方面的努力,也是其中的一个比较独特的部分。以前,安装 Linux 是个最好让有技术的人来干的任务。现在,只要你会装软件,你就会安装 Linux。简单并且不是我吹在吸引新用户方面效果拔群。事实上相较于 Windows 你可以更快的完成整个 Linux 操作系统的安装,更新也更快点。
我用 Linux 有些年头了。在这些年里我很有幸见证了开源的发展。各色各样的发行版在安装方面的努力,也是其中的一个比较独特的部分。以前,安装 Linux 是个最好让有技术的人来干的任务。现在,只要你会装软件,你就会安装 Linux。简单并且不是我吹在吸引新用户方面效果拔群。事实上安装整个 Linux 操作系统都要比 Windows 用户安装个更新看起来要快一点。
即使很频繁,我也乐得见到其中有所不同——让我知道我从哪来,要干啥。[NixOS][9] 在这方面就做的别具一格。讲真,我原来也就把它当作另一个提供标准特性和 KDE Plasma 5 界面的 Linux 发行版。
但每一次,我都喜欢看到一些不同的东西——那些可以让我体验新鲜的东西。[NixOS][9] 在这方面就做的别具一格。讲真,我原来也就把它当作另一个提供标准特性和 KDE Plasma 5 界面的 Linux 发行版。
好像也没什么不对。
[下载 ISO 映像][10]后,我启动了 [VirtualBox][11] 并用下载的镜像创建了个新的虚拟机。VM 启动后,出来的是 Bash 的登录界面,界面上指导我用空密码去登录 root 账号,以及我该如何启动 GUI 显示管理器(图 1
### [nixos_1.jpg][5]
![First contact](https://www.linux.com/sites/lcom/files/styles/rendered_file/public/nixos_1.jpg?itok=VkGTO2Tg "First contact")
图 1 与 NixOS 的初次接触可能不是太和谐。[使用许可][1]
*图 1 与 NixOS 的初次接触可能不是太和谐。*
“好吧”我这样想着,“打开看看吧!”
GUI 启动和运行KDE Plasma 5我没找到喜闻乐见的“安装”按钮。原来NixOS 是一个在安装前需要你配置的发行版,真有趣。那就让我们瞧瞧它是如何做到的吧!
GUI 启动和运行KDE Plasma 5我没找到喜闻乐见的“安装”按钮。原来NixOS 是一个在安装前需要你配置的发行版,真有趣。那就让我们瞧瞧它是如何做到的吧!
### 安装前配置
你需要做的第一件事是建分区。由于 NixOS 安装程序不包含分区工具,你得用自带的 GParted (图 2来创建一个 EXT4 分区。
### [nixos_2.jpg][6]
![Partitioning](https://www.linux.com/sites/lcom/files/styles/rendered_file/public/nixos_2.jpg?itok=nta-bl-S "Partitioning")
图 2 安装前的分区。[使用许可][2]
*图 2 安装前对磁盘分区。*
创建好分区,然后用命令 _mount /dev/sdX /mnt _ 挂载。(请自行替换 sdX 为你新创建的分区)。
创建好分区,然后用命令 `mount /dev/sdX /mnt` 挂载。(请自行替换 `sdX` 为你新创建的分区)。
你现在需要创建一个配置文件。命令如下:
@ -41,31 +37,26 @@ GUI 启动和运行KDE Plasma 5我没找到喜闻乐见的“安装
nixos-generate-config --root /mnt
```
上面的命令会创建两个文件(存放在目录 _/mnt/etc/nixos_ 中):
上面的命令会创建两个文件(存放在目录 `/mnt/etc/nixos` 中):
* configuration.nix — 默认配置文件。
* `configuration.nix` — 默认配置文件。
* `hardware-configuration.nix` — 硬件配置(无法编辑)
* hardware-configuration.nix — 硬件配置(无法编辑)
通过命令 _nano /mnt/etc/nixos/configuration.nix_ 打开文件。其中有一些需要编辑的地方得注意。第一个改动便是设置启动选项。找到行:
通过命令 `nano /mnt/etc/nixos/configuration.nix` 打开文件。其中有一些需要编辑的地方得注意。第一个改动便是设置启动选项。找到行:
```
# boot.loader.grub.device = “/dev/sda”; # or “nodev” for efi only
# boot.loader.grub.device = "/dev/sda"; # 或 efi 时用 "nodev"
```
删除行首的 # 使该选项生效(确保 /dev/sda 与是新建分区一致)。
删除行首的 `#` 使该选项生效(确保 `/dev/sda` 与你新建的分区)。
通过配置文件,你可以设置时区和追加要安装的软件包。来看一个被注释掉的安装包的示例:
```
# List packages installed in system profile. To search by name, run:
# nix-env -aqP | grep wget
# environment.systemPackages = with pkgs; [
# wget vim
# wget vim
# ];
```
@ -73,61 +64,53 @@ nixos-generate-config --root /mnt
```
# List packages installed in system profile. To search by name, run:
nix-env -aqP | grep wget
environment.systemPackages = with pkgs; [
libreoffice wget vim
libreoffice wget vim
];
```
你可以通过输入命令 _nix-env -aqP | grep PACKAGENAME _ 来寻找确切的包名PACKAGENAME 为你想要找的软件包)。如果你不想输命令,你也可以检索 [NixOS 的软件包数据库][12]。
你可以通过输入命令 `nix-env -aqP | grep PACKAGENAME` 来寻找确切的包名(`PACKAGENAME` 为你想要找的软件包)。如果你不想输命令,你也可以检索 [NixOS 的软件包数据库][12]。
在你把所有的软件包都添加完后,你还有件事儿需要做(如果你想要登录到桌面的话,我觉得你还得折腾下 KDE Plasma 5 桌面)。翻到配置文件的末尾并在最后的 } 符号前,追加如下内容:
在你把所有的软件包都添加完后,你还有件事儿需要做(如果你想要登录到桌面的话,我觉得你还得折腾下 KDE Plasma 5 桌面)。翻到配置文件的末尾并在最后的 `}` 符号前,追加如下内容:
```
services.xserver = {
enable = true;
displayManager.sddm.enable = true;
desktopManager.plasma5.enable = true;
};
```
在 [NixOS 官方文件][13] 中,你能找到配置文件中更多的选项。保存并关掉配置文件。
### 安装
### 安装
在你按照自己的需求完善好配置之后,使用命令(需要 root 权限) nixos-install。完成安装所需要的时间会随着你加入的软件包多少有所区别。安装结束后你可以使用命令重启系统重启之后迎接你的就是 KDE Plasma 5 的登录管理界面了(图 3
### [nixos_3.jpg][7]
在你按照自己的需求完善好配置之后,使用命令(需要 root 权限) `nixos-install`。完成安装所需要的时间,会随着你加入的软件包多少有所区别。安装结束后,你可以使用命令重启系统,(重启之后)迎接你的就是 KDE Plasma 5 的登录管理界面了(图 3
![KDE Plasma 5](https://www.linux.com/sites/lcom/files/styles/rendered_file/public/nixos_3.jpg?itok=DdsB5opR "KDE Plasma 5")
图 3 KDE Plasma 5 登录管理界面[使用许可][3]
*图 3 KDE Plasma 5 登录管理界面*
### 安装后
你要首先要做的两件事之一便是给 root 用户设个密码(通过输入命令 _passwd_ 来修改默认的密码),以及添加一个标准用户。做法和其它的 Linux 发行版无二。用 root 用户登录,然后在终端输入命令:
你要首先要做的两件事之一便是给 root 用户设个密码(通过输入命令 `passwd` 来修改默认的密码),以及添加一个标准用户。做法和其它的 Linux 发行版无二。用 root 用户登录,然后在终端输入命令:
```
useradd -m USER
```
将 USER 替换成你想要添加的用户名。然后通过下面的命令给用户设上密码:
`USER` 替换成你想要添加的用户名。然后通过下面的命令给用户设上密码:
```
passwd USER
```
同样的将 USER 替换成你添加的用户。然后会有提示引导你填写并验证新密码。然后,你就能用标准用户登录 NixOS 啦。
同样的将 `USER` 替换成你添加的用户。
NixOS 在你安装并运行后,你可以为系统添加新的软件包,但并非通过寻常的方式。如果你发现你需要安装些新东西,你得回到配置文件(位置就是 _/etc/nixos/_ ),找到之前安装时添加软件包的位置,运行以下命令(需要 root 权限):
然后会有提示引导你填写并验证新密码。然后,你就能用标准用户登录 NixOS 啦。
NixOS 在你安装并运行后,你可以为系统添加新的软件包,但并非通过寻常的方式。如果你发现你需要安装些新东西,你得回到配置文件(位置就是 `/etc/nixos/` ),找到之前安装时添加软件包的位置,运行以下命令(需要 root 权限):
```
nixos-rebuild switch
@ -145,7 +128,7 @@ via: https://www.linux.com/learn/intro-to-linux/2017/10/nixos-linux-lets-you-con
作者:[JACK WALLEN][a]
译者:[martin2011qi](https://github.com/martin2011qi)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -0,0 +1,41 @@
Cloud Integrated Advanced Orchestrator
============================================================
Cloud Integrated Advanced Orchestrator (ciao) is a new workload scheduler designed to address limitations in current cloud OS projects. Ciao provides a lightweight, fully TLS-based, minimal Config. It is workload-agnostic, easily updateable, has an optimized-for-speed scheduler, and is currently optimized for OpenStack*.
Design decisions and the innovative approach were informed by requirements for security, scalability, usability, and deployability:
**Scalability:** The initial design targets are to scale past 5,000 nodes. Thus, the scheduler architecture is approached in a new way:
In ciao, decision-making is decentralized. It is based on a pull model, allowing compute nodes to request jobs from the scheduling agent. The scheduler is always aware of the launchers capacities, never asking for updates, and the scheduling decision time is kept to a minimum. Launchers asynchronously send capacity to the scheduler.
Tracking of persistent state is separated from scheduler decision-making, allowing the scheduler to remain lightweight. This separation increases reliability, scalability, and performance. The result is that the scheduler gets out of the way and is not a bottleneck.
**Usability:** Virtual machines, containers, and bare metal are integrated into one scheduler; all workloads are treated as equal citizens. For further ease of use, networking is simplified with a minimalist, asynchronous protocol between components, requiring minimal configuration. Ciao also includes a new, simple UI. Integration of all these functions leads to simpler installation, configuration, maintenance, and operation.
**Ease of Deployment:** Upgrade should be the expectation, not the exception. This new architecture, with decentralization of state, allows for seamless upgrades. To make sure that the infrastructure (e.g. OpenStack) is always up to date, a Continuous Integration/Continuous Delivery (CI/CD) model is implemented. Ciao is designed so that one can kill any Ciao component on the fly, replace it, and restart it with minimal impact on availability.
**Security is mandatory:** Connections to the scheduler are always encrypted: SSL is on by default, not off. Encryption is from end to end: HTTPS is required for all external connections, and internal communication between components is TLS-based. Integration of networking support guarantees tenant separation.
Initial results are proving to be significant: 10k Docker Containers and 5k VMs in 65 seconds. Further optimization is ongoing.
Documentation: [https://clearlinux.org/documentation/ciao/ciao.html][3]
Github link: [https://github.com/01org/ciao(link is external)][1]
Mailing list link: [https://lists.clearlinux.org/mailman/listinfo/ciao-devel][2]
--------------------------------------------------------------------------------
via: https://clearlinux.org/ciao
作者:[ciao][a]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://clearlinux.org/ciao
[1]:https://github.com/01org/ciao
[2]:https://lists.clearlinux.org/mailman/listinfo/ciao-devel
[3]:https://clearlinux.org/documentation/ciao/ciao.html

View File

@ -0,0 +1,67 @@
# Introducing CRI-O 1.0
Last year, the Kubernetes project introduced its [Container Runtime Interface][11] (CRI) -- a plugin interface that gives kubelet (a cluster node agent used to create pods and start containers) the ability to use different OCI-compliant container runtimes, without needing to recompile Kubernetes. Building on that work, the [CRI-O][12] project ([originally known as OCID][13]) is ready to provide a lightweight runtime for Kubernetes.
So what does this **really** mean?
CRI-O allows you to run containers directly from Kubernetes - without any unnecessary code or tooling. As long as the container is OCI-compliant, CRI-O can run it, cutting out extraneous tooling and allowing containers to do what they do best: fuel your next-generation cloud-native applications
Prior to the introduction of CRI, Kubernetes was tied to specific container runtimes through “[an internal and ][14][volatile ][15][interface][16].” This incurred a significant maintenance overhead for the upstream Kubernetes community as well as vendors building solutions on top of the orchestration platform.
With CRI, Kubernetes can be container runtime-agnostic. Providers of container runtimes dont need to implement features that Kubernetes already provides. This is a win for the broad community, as it allows projects to move independently while still working well together.
For the most part, we dont think users of Kubernetes (or distributions of Kubernetes, like OpenShift) really care a lot about the container runtime. They want it to work, but they dont really want to think about it a great deal. Sort of like you dont (usually) care if a machine has GNU Bash, Korn, Zsh, or another POSIX-compliant shell. You just want to have a standard way to run your script or application.
**CRI-O: A Lightweight Container Runtime for Kubernetes**
And thats what CRI-O provides. The name derives from CRI plus Open Container Initiative (OCI), because CRI-O is strictly focused on OCI-compliant runtimes and container images.
Today, CRI-O supports the runc and Clear Container runtimes, though it should support any OCI-conformant runtime. It can pull images from any container registry, and handles networking using the [Container Network Interface][17] (CNI) so that any CNI-compatible networking plugin will likely work with the project.
When Kubernetes needs to run a container, it talks to CRI-O and the CRI-O daemon works with runc (or another OCI-compliant runtime) to start the container. When Kubernetes needs to stop the container, CRI-O handles that. Nothing exciting, it just works behind the scenes to manage Linux containers so that users dont need to worry about this crucial piece of container orchestration.
![CRI-O Overview](https://www.redhat.com/cms/managed-files/styles/max_size/s3/CRI-Ov1_Chart_1.png?itok=2FJxD8Qp "CRI-O Overview")
**What CRI-O isnt**
Its worth spending a little time on what CRI-O  _isnt_ . The scope for CRI-O is to work with Kubernetes, to manage and run OCI containers. Its not meant as a developer-facing tool, though the project does have some user-facing tools for troubleshooting.
Building images, for example, is out of scope for CRI-O and thats left to tools like Dockers build command, [Buildah][18], or [OpenShifts Source-to-Image][19] (S2I). Once an image is built, CRI-O will happily consume it, but the building of images is left to other tools.
While CRI-O does include a command line interface (CLI), its provided mainly for testing CRI-O and not really as a method for managing containers in a production environment.
**Next steps**
Now that CRI-O 1.0 is released, were hoping to see it included as a stable feature in the next release of Kubernetes. The 1.0 release will work with the Kubernetes 1.7.x series, a CRI-O 1.8-rc1 release for Kubernetes 1.8.x will be released soon.
We invite you to join us in furthering the development of the Open Source CRI-O project and we would like to thank our current contributors for their assistance in reaching this milestone. If you would like to contribute, or follow development, head to [CRI-O projects GitHub repository][20] and follow the [CRI-O blog][21].
--------------------------------------------------------------------------------
via: https://www.redhat.com/en/blog/introducing-cri-o-10
作者:[Joe Brockmeier][a]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.redhat.com/en/blog/authors/joe-brockmeier
[1]:https://www.redhat.com/en/blog/authors/joe-brockmeier
[2]:https://www.redhat.com/en/blog/authors/senior-evangelist
[3]:https://www.redhat.com/en/blog/authors/linux-containers
[4]:https://www.redhat.com/en/blog/authors/red-hat-0
[5]:https://www.redhat.com/en/blog
[6]:https://www.redhat.com/en/blog/tag/community
[7]:https://www.redhat.com/en/blog/tag/containers
[8]:https://www.redhat.com/en/blog/tag/hybrid-cloud
[9]:https://www.redhat.com/en/blog/tag/platform
[10]:mailto:?subject=Check%20out%20this%20redhat.com%20page:%20Introducing%20CRI-O%201.0&body=I%20saw%20this%20on%20redhat.com%20and%20thought%20you%20might%20be%20interested.%20%20Click%20the%20following%20link%20to%20read:%20https://www.redhat.com/en/blog/introducing-cri-o-10https://www.redhat.com/en/blog/introducing-cri-o-10
[11]:https://github.com/kubernetes/kubernetes/blob/242a97307b34076d5d8f5bbeb154fa4d97c9ef1d/docs/devel/container-runtime-interface.md
[12]:http://cri-o.io/
[13]:https://www.redhat.com/en/blog/running-production-applications-containers-introducing-ocid
[14]:http://blog.kubernetes.io/2016/12/container-runtime-interface-cri-in-kubernetes.html
[15]:http://blog.kubernetes.io/2016/12/container-runtime-interface-cri-in-kubernetes.html
[16]:http://blog.kubernetes.io/2016/12/container-runtime-interface-cri-in-kubernetes.html
[17]:https://github.com/containernetworking/cni
[18]:https://github.com/projectatomic/buildah
[19]:https://github.com/openshift/source-to-image
[20]:https://github.com/kubernetes-incubator/cri-o
[21]:https://medium.com/cri-o

View File

@ -0,0 +1,53 @@
[How to deploy multi-cloud serverless and Cloud Foundry APIs at scale][2]
============================================================
“Micro-services and APIs are products and we need to think about them that way,” says IBMs Ken Parmelee.
![](https://1.gravatar.com/avatar/df4717dffc99e14633358825d9e4f7f2?s=45&d=http%3A%2F%2Fsuperuser.openstack.org%2Fwp-content%2Fthemes%2Fsuperuser%2Fimages%2Fsocial-icon-bracket.png&r=g)
Ken Parmelee, who leads the API gateway for IBM and Big Blues open source projects, has a few ideas about open-source methods for “attacking” the API and how to create micro-services and make them scale.
“Micro-services and APIs are products and we need to be thinking about them that way,” Parmelee says. “As you start to put them up people rely on them as part of their business. Thats a key aspect of what youre doing in this space.”
![](http://superuser.openstack.org/wp-content/uploads/2017/10/Screen-Shot-2017-10-16-at-10.49.26-595x277.png)
He took the stage at the recent [Nordic APIs 2017 Platform Summit][3] and challenged a few popular notions.
“Fail fast is not really a good concept. You want to get something out there thats fantastic on the first run. That doesnt mean you need to take tons of time, but make it fantastic then keep evolving and improving. If its really bad in the beginning, people arent going to want to stick with you.”
He runs through IBMs modern serverless architectures including [OpenWhisk][4], an open source partnership between IBM and Apache. The cloud-first distributed event-based programming service is result of focusing on this space for over two years; IBM is a leading contributor and it serves as the foundation of IBM cloud functions. It offers infrastructure-as-a-service, automatically scales, offers support for multiple languages and users pay only for what they actually use. Challenges were also a part of this journey, as they discovered that servers actions need securing and require ease — anonymous access, missing usage trails, fixed URL schemes etc.
Anyone can try out these serverless APIs in just 30 seconds at [https://console.bluemix.net/openwhisk/][5] “This sounds very gimmicky, but it is that easy to do…Were combining the [work weve done with Cloud Foundry ][6]and released them in Bluemix under the OpenWhisk to provide security and scalability.”
“Flexibility is also hugely important for micro-services,” he says. “When youre working in the real world with APIs, you start to have to scale across clouds.” That means from your on-premise cloud to the public cloud and “having an honest concept of how youre going to do that is important.
![](http://superuser.openstack.org/wp-content/uploads/2017/10/Screen-Shot-2017-10-16-at-14.51.06-595x274.png)
And when thinking about the “any cloud concept” he warns that its not “throw it into any Docker container and it runs anywhere. Thats great but it needs to run effectively in those environments. Docker and Kubernetes help a lot, but you want to operationalize how youre going to do it.” Think ahead on the consumption of your API whether its running only internally or will expand to a public cloud and be publicly consumable you need have that “architectural view,” he adds.
“We all hope that what we create has value and gets consumed a lot,” Parmelee says. The more successful the API, the bigger the challenge of taking it to the next level.
![](http://superuser.openstack.org/wp-content/uploads/2017/10/Screen-Shot-2017-10-16-at-15.01.00-595x299.png)
APIs are building blocks for micro-services or “inter-services.”
The future of APIs is cloud native — regardless of where you start, he says. Key factors are scalability, simplifying back-end management, cost and avoiding vendor lock-in.
You can catch his entire 23-minute talk below or on [YouTube][7].
--------------------------------------------------------------------------------
via: http://superuser.openstack.org/articles/deploy-multi-cloud-serverless-cloud-foundry-apis-scale/
作者:[Superuser ][a]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:http://superuser.openstack.org/articles/author/superuser/
[1]:http://superuser.openstack.org/articles/author/superuser/
[2]:http://superuser.openstack.org/articles/deploy-multi-cloud-serverless-cloud-foundry-apis-scale/
[3]:https://nordicapis.com/events/the-2017-api-platform-summit/
[4]:https://developer.ibm.com/openwhisk/
[5]:https://console.bluemix.net/openwhisk/
[6]:https://cloudfoundry.org/the-foundry/ibm-cloud/
[7]:https://www.youtube.com/jA25Kmxr6fU

View File

@ -0,0 +1,41 @@
Linus Torvalds says targeted fuzzing is improving Linux security
============================================================
Linux 4.14 release candidate five is out. "Go out and test," says Linus Torvalds.
![linus-toravlds-linuxcon-toronto.jpg](http://zdnet4.cbsistatic.com/hub/i/r/2016/09/13/02537e55-6620-4c3b-aa09-c9c068f3823b/resize/770xauto/b866caa8695edbec68f67da0e9a411e9/linus-toravlds-linuxcon-toronto.jpg)
Announcing the fifth release candidate for the Linux kernel version 4.14, Linus Torvalds has revealed that fuzzing is producing a steady stream of security fixes.
Fuzzing involves stress testing a system by generating random code to induce errors, which in turn may help identify potential security flaws. Fuzzing is helping software developers catch bugs before shipping software to users.
Google uses a variety of fuzzing tools to find bugs in its and other vendors' software. Microsoft has launched the [Project Springfield][1] fuzzing service to allow enterprise customers to test their own software.
As Torvalds points out, Linux kernel developers have been using fuzzing programs since the beginning, such as tools like "crashme", which was released in 1991 and nearly 20 years later was [used by Google security researcher Tavis Ormandy][2] to test how well shielded a host is when untrusted data is being processed in a virtual machine.
"The other thing perhaps worth mentioning is how much random fuzzing people are doing, and it's finding things," [writes][3] Torvalds.
"We've always done fuzzing (who remembers the old "crashme" program that just generated random code and jumped to it? We used to do that quite actively very early on), but people have been doing some nice targeted fuzzing of driver subsystems etc, and there's been various fixes (not just this last week either) coming out of those efforts. Very nice to see."
Torvalds mentions that 4.14's development has until now "felt a bit messier than perhaps should have been" but has now smoothed out, and runs through some of the fixes in this build for x86 systems and systems with AMD chips. There are also updates for several drivers, core kernel components, and tooling.
As previously [reported][4], Linux 4.14 is 2017's Long-Term Stable release, which has so far introduced core memory management features, device driver updates, and changes to documentation, architecture, filesystems, networking and tooling.
--------------------------------------------------------------------------------
via: http://www.zdnet.com/article/linus-torvalds-says-targeted-fuzzing-is-improving-linux-security/
作者:[Liam Tung ][a]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:http://www.zdnet.com/meet-the-team/eu/liam-tung/
[1]:http://www.zdnet.com/article/microsoft-seeks-testers-for-project-springfield-bug-detection-service/
[2]:http://taviso.decsystem.org/virtsec.pdf
[3]:http://lkml.iu.edu/hypermail/linux/kernel/1710.1/06454.html
[4]:http://www.zdnet.com/article/first-linux-4-14-release-adds-very-core-features-arrives-in-time-for-kernels-26th-birthday/
[5]:http://www.zdnet.com/meet-the-team/eu/liam-tung/
[6]:http://www.zdnet.com/meet-the-team/eu/liam-tung/
[7]:http://www.zdnet.com/topic/security/

View File

@ -1,32 +1,23 @@
Translating by trnhoe.
An introduction to functional programming in JavaScript
JavaScript 函数式编程介绍
============================================================
### Explore functional programming and how using it can make your programs easier to read and debug.
### 探索函数式编程和通过它让你的程序更具有可读性和易于调试
![An introduction to functional programming in JavaScript](https://opensource.com/sites/default/files/styles/image-full-size/public/images/business/bus-rocket.png?itok=vHKRzkyW "An introduction to functional programming in JavaScript")
>Image credits : Steve Jurvetson via [Flickr][80] (CC-BY-2.0)
When Brendan Eich created JavaScript in 1995, he intended to do [Scheme in the browser][81]. Scheme, being a dialect of Lisp, is a functional programming language. Things changed when Eich was told that the new language should be the scripting language companion to Java. Eich eventually settled on a language that has a C-style syntax (as does Java), yet has first-class functions. Java technically did not have first-class functions until version 8, however you could simulate first-class functions using anonymous classes. Those first-class functions are what makes functional programming possible in JavaScript.
当 Brendan Eich 在 1995 年创造了 JavaScript他打算[将 Scheme 移植到浏览器里][81] 。Scheme 作为 Lisp 的方言,是一种函数式编程语言。而当 Eich 被告知新的语言应该是一种可以与 Java 相比的脚本语言后,他最终确立了一种拥有 C 风格语法的语言(也和 Java 一样但将函数视作一等公民。Java 直到版本 8 才从技术上将函数视为一等公民,虽然你可以用匿名类来模拟它。这个特性允许 JavaScript 通过函数式范式编程。
JavaScript is a multi-paradigm language that allows you to freely mix and match object-oriented, procedural, and functional paradigms. Recently there has been a growing trend toward functional programming. In frameworks such as [Angular][82]and [React][83], you'll actually get a performance boost by using immutable data structures. Immutability is a core tenet of functional programming. It, along with pure functions, makes it easier to reason about and debug your programs. Replacing procedural loops with functions can increase the readability of your program and make it more elegant. Overall, there are many advantages to functional programming.
JavaScript 是一个多范式语言,允许你自由地混合和使用面向对象式,过程式和函数式的范式。最近,函数式编程越来越火热。在诸如 [Angular][82] 和 [React ][83]这样的框架中,通过使用不可变数据结构实际上可以提高性能。不可变是函数式编程的核心原则,纯函数和它使得编写和调试程序变得更加容易。使用函数来代替程序的循环可以提高程序的可读性并使它更加优雅。总之,函数式编程拥有很多优点。
### What functional programming isn't
### 什么不是函数式编程
Before we talk about what functional programming is, let's talk about what it is not. In fact, let's talk about all the language constructs you should throw out (goodbye, old friends):
在讨论什么是函数式编程前,让我们先排除那些不属于函数式编程的东西。实际上它们是你需要丢弃的语言组件(再见,老朋友):
Programming and development
* [New Python content][1]
* [Our latest JavaScript articles][2]
* [Recent Perl posts][3]
* [Red Hat Developers Blog][4]
* Loops
* 循环
* **while**
* **do...while**
@ -36,14 +27,10 @@ Programming and development
* **for...of**
* **for...in**
* Variable declarations with **var** or **let**
* Void functions
* Object mutation (for example: **o.x = 5;**)
* Array mutator methods
* 用 **var** 或者 **let** 来声明变量
* 没有返回值的函数
* 改变对象的属性 (比如: **o.x = 5;**)
* 改变 Array 本身的方法
* **copyWithin**
* **fill**
@ -61,32 +48,29 @@ Programming and development
* **splice**
* **unshift**
* Map mutator methods
* 改变 Map 本身的方法
* **clear**
* **delete**
* **set**
* Set mutator methods
* 改变 Set 本身的方法
* **add**
* **clear**
* **delete**
How can you possibly program without those features? That's exactly what we are going to explore in the next few sections.
脱离这些特性应该如何编写程序呢?这是我们将在后面探索的问题。
### Pure functions
### 纯函数
Just because your program contains functions does not necessarily mean that you are doing functional programming. Functional programming distinguishes between pure and impure functions. It encourages you to write pure functions. A pure function must satisfy both of the following properties:
你的程序中包含函数不一定意味着你正在进行函数式编程。函数式范式将纯函数和非纯函数区分开。鼓励你编写纯函数。纯函数必须满足下面的两个属性:
* **Referential transparency:** The function always gives the same return value for the same arguments. This means that the function cannot depend on any mutable state.
* **引用透明:**函数在传入相同的参数后永远返回相同的返回值。这意味着该函数不依赖于任何可变状态。
* **Side-effect free无函数副作用:**函数不能导致任何副作用。副作用可能包括 I/O(比如 向终端或者日志文件写入),改变一个不可变的对象,对变量重新赋值等等。
* **Side-effect free:** The function cannot cause any side effects. Side effects may include I/O (e.g., writing to the console or a log file), modifying a mutable object, reassigning a variable, etc.
Let's illustrate with a few examples. First, the **multiply** function is an example of a pure function. It always returns the same output for the same input, and it causes no side effects.
我们来看一些例子。首先,**multiply** 就是一个纯函数的例子,它在传入相同的参数后永远返回相同的返回值,并且不会导致副作用。
```
@ -97,7 +81,7 @@ function multiply(a, b) {
[view raw][5][pure-function-example.js][6] hosted with ❤ by [GitHub][7]
The following are examples of impure functions. The **canRide** function depends on the captured **heightRequirement** variable. Captured variables do not necessarily make a function impure, but mutable (or re-assignable) ones do. In this case it was declared using **let**, which means that it can be reassigned. The **multiply** function is impure because it causes a side-effect by logging to the console.
下面是非纯函数的例子。**canRide** 函数依赖捕获的 **heightRequirement** 变量。被捕获的变量不一定导致一个函数是非纯函数,除非它是一个可变的变量(或者可以被重新赋值)。这种情况下使用  **let** 来声明这个变量,意味着可以对它重新赋值。**multiply** 函数是非纯函数,因为它会导致在 console 上输出。
```
let heightRequirement = 46;
@ -117,7 +101,7 @@ function multiply(a, b) {
[view raw][8][impure-functions.js][9] hosted with ❤ by [GitHub][10]
The following list contains several built-in functions in JavaScript that are impure. Can you state which of the two properties each one does not satisfy?
下面的列表包含着 JavaScript 内置的非纯函数。你可以指出它们不满足两个属性中的哪个吗?
* **console.log**
@ -127,23 +111,23 @@ The following list contains several built-in functions in JavaScript that are im
* **Date.now**
* **$.ajax** (where **$** == the Ajax library of your choice)
* **$.ajax** (**$** 代表你使用的 Ajax 库)
Living in a perfect world in which all our functions are pure would be nice, but as you can tell from the list above, any meaningful program will contain impure functions. Most of the time we will need to make an Ajax call, check the current date, or get a random number. A good rule of thumb is to follow the 80/20 rule: 80% of your functions should be pure, and the remaining 20%, of necessity, will be impure.
理想的程序中所有的函数都是纯函数,但是从上面的函数列表可以看出,任何有意义的程序都将包含非纯函数。大多时候我们需要进行 AJAX 调用检查当前日期或者获取一个随机数。一个好的经验法则是遵循80/20规则函数中有80应该是纯函数剩下的20的必要性将不可避免地是非纯函数。
There are several benefits to pure functions:
使用纯函数有几个优点:
* They're easier to reason about and debug because they don't depend on mutable state.
* 它们很容易导出和调试,因为它们不依赖于可变的状态。
* The return value can be cached or "memoized" to avoid recomputing it in the future.
* 返回值可以被缓存或者“记忆”来避免以后重复计算。
* They're easier to test because there are no dependencies (such as logging, Ajax, database, etc.) that need to be mocked.
* 它们很容易测试因为没有需要模拟mock的依赖比如日志AJAX数据库等等
If a function you're writing or using is void (i.e., it has no return value), that's a clue that it's impure. If the function has no return value, then either it's a no-op or it's causing some side effect. Along the same lines, if you call a function but do not use its return value, again, you're probably relying on it to do some side effect, and it is an impure function.
你编写或者使用的函数返回空(换句话说它没有返回值),那代表它是非纯函数。
### Immutability
### 不变性
Let's return to the concept of captured variables. Above, we looked at the **canRide** function. We decided that it is an impure function, because the **heightRequirement** could be reassigned. Here is a contrived example of how it can be reassigned with unpredictable results:
让我们回到捕获变量的概念上。来看看 **canRide** 函数。我们认为它是一个非纯函数,因为 **heightRequirement** 变量可以被重新赋值。下面是一个构造出来的例子来说明如何用不可预测的值来对它重新赋值。
```
let heightRequirement = 46;
@ -165,7 +149,7 @@ setInterval(() => console.log(canRide(mySonsHeight)), 500);
[view raw][11][mutable-state.js][12] hosted with ❤ by [GitHub][13]
Let me reemphasize that captured variables do not necessarily make a function impure. We can rewrite the **canRide** function so that it is pure by simply changing how we declare the **heightRequirement** variable.
我要再次强调被捕获的变量不一定会使函数成为非纯函数。我们可以通过只是简单地改变 **heightRequirement** 的声明方式来使 **canRide** 函数成为纯函数。
```
const heightRequirement = 46;
@ -178,7 +162,7 @@ function canRide(height) {
[view raw][14][immutable-state.js][15] hosted with ❤ by [GitHub][16]
Declaring the variable with **const** means that there is no chance that it will be reassigned. If an attempt is made to reassign it, the runtime engine will throw an error; however, what if instead of a simple number we had an object that stored all our "constants"?
通过用 **const** 来声明变量意味着它不能被再次赋值。如果尝试对它重新赋值,运行时引擎将抛出错误;那么,如果用对象来代替数字来存储所有的“常量”怎么样?
```
const constants = {
@ -194,55 +178,55 @@ function canRide(height) {
[view raw][17][captured-mutable-object.js][18] hosted with ❤ by [GitHub][19]
We used **const** so the variable cannot be reassigned, but there's still a problem. The object can be mutated. As the following code illustrates, to gain true immutability, you need to prevent the variable from being reassigned, and you also need immutable data structures. The JavaScript language provides us with the **Object.freeze** method to prevent an object from being mutated.
我们用了 **const** 所以这个变量不能被重新赋值但是还有一个问题这个对象可以被改变。下面的代码展示了为了真正使其不可变你不仅需要防止它被重新赋值你也需要不可变的数据结构。JavaScript 语言提供了 **Object.freeze** 方法来阻止对象被改变。
```
'use strict';
// CASE 1: The object is mutable and the variable can be reassigned.
// CASE 1: The object is mutable and the variable can be reassigned.对象的属性是可变的,并且变量可以被再次赋值。
let o1 = { foo: 'bar' };
// Mutate the object
// Mutate the object改变对象的属性
o1.foo = 'something different';
// Reassign the variable
// Reassign the variable对变量再次赋值
o1 = { message: "I'm a completely new object" };
// CASE 2: The object is still mutable but the variable cannot be reassigned.
// CASE 2: The object is still mutable but the variable cannot be reassigned.对象的属性还是可变的,但是变量不能被再次赋值。
const o2 = { foo: 'baz' };
// Can still mutate the object
o2.foo = 'Something different, yet again';
// Cannot reassign the variable
// Cannot reassign the variable不能对变量再次赋值
// o2 = { message: 'I will cause an error if you uncomment me' }; // Error!
// CASE 3: The object is immutable but the variable can be reassigned.
// CASE 3: The object is immutable but the variable can be reassigned.对象的属性是不可变的,但是变量可以被再次赋值。
let o3 = Object.freeze({ foo: "Can't mutate me" });
// Cannot mutate the object
// Cannot mutate the object不能改变对象的属性
// o3.foo = 'Come on, uncomment me. I dare ya!'; // Error!
// Can still reassign the variable
// Can still reassign the variable还是可以对变量再次赋值
o3 = { message: "I'm some other object, and I'm even mutable -- so take that!" };
// CASE 4: The object is immutable and the variable cannot be reassigned. This is what we want!!!!!!!!
// CASE 4: The object is immutable and the variable cannot be reassigned. This is what we want!!!!!!!!对象的属性是不可变的,并且变量不能被再次赋值。这是我们想要的!!!!!!!!
const o4 = Object.freeze({ foo: 'never going to change me' });
// Cannot mutate the object
// Cannot mutate the object不能改变对象的属性
// o4.foo = 'talk to the hand' // Error!
// Cannot reassign the variable
// Cannot reassign the variable不能对变量再次赋值
// o4 = { message: "ain't gonna happen, sorry" }; // Error
```
[view raw][20][immutability-vs-reassignment.js][21] hosted with ❤ by [GitHub][22]
Immutability pertains to all data structures, which includes arrays, maps, and sets. That means that we cannot call mutator methods such as **array.prototype.push** because that modifies the existing array. Instead of pushing an item onto the existing array, we can create a new array with all the same items as the original array, plus the one additional item. In fact, every mutator method can be replaced by a function that returns a new array with the desired changes.
不变性适用于所有的数据结构,包括数组,映射和集合。它意味着不能调用例如 **Array.prototype.push** 等会导致本身改变的方法,因为它会改变已经存在的数组。可以通过创建一个含有原来元素和新加元素的新数组,代替将新元素加入一个已经存在的数组。其实所有会导致数组本身被修改的方法都可以通过一个返回修改好的新数组的函数代替。**这里一段mutator的翻译大概有些啰嗦。**
```
'use strict';
@ -267,7 +251,7 @@ const f = R.sort(myCompareFunction, a); // R = Ramda
// Instead of: a.reverse();
const g = R.reverse(a); // R = Ramda
// Exercise for the reader:
// Exercise for the reader留给读者的练习:
// copyWithin
// fill
// splice
@ -276,7 +260,7 @@ const g = R.reverse(a); // R = Ramda
[view raw][23][array-mutator-method-replacement.js][24] hosted with ❤ by [GitHub][25]
The same thing goes when using a [**Map**][84] or a [**Set**][85]. We can avoid mutator methods by returning a new **Map** or **Set** with the desired changes.
[**Map**][84] 和 [**Set**][85] 也很相似。可以通过返回一个新的修改好的 Map 或者 Set 来代替使用会修改其本身的函数。
```
const map = new Map([
@ -314,7 +298,7 @@ const set4 = new Set();
[view raw][29][set-mutator-method-replacement.js][30] hosted with ❤ by [GitHub][31]
I would like to add that if you are using TypeScript (I am a huge fan of TypeScript), then you can use the **Readonly<T>**, **ReadonlyArray<T>**, **ReadonlyMap<K, V>**, and **ReadonlySet<T>** interfaces to get a compile-time error if you attempt to mutate any of those objects. If you call **Object.freeze** on an object literal or an array, then the compiler will automatically infer that it is read-only. Because of how Maps and Sets are represented internally, calling **Object.freeze** on those data structures does not work the same. But it's easy enough to tell the compiler that you would like them to be read-only.
我想提一句如果你在使用 TypeScript我非常喜欢TypeScript你可以用 **Readonly<T>**, **ReadonlyArray<T>**, **ReadonlyMap<K, V>**, 和 **ReadonlySet<T>** 接口来在编译期检查你是否尝试更改这些对象,有则抛出编译错误。如果在对一个对象字面量或者数组调用 **Object.freeze**,编译器会自动推断它是只读的。由于映射和集合在其内部表达,所以在这些数据结构上调用 **Object.freeze** 不起作用。但是你可以轻松地告诉编译器它们是只读的变量。
### [typescript-readonly.png][32]
@ -323,7 +307,7 @@ I would like to add that if you are using TypeScript (I am a huge fan of TypeScr
TypeScript read-only interfaces
Okay, so we can create new objects instead of mutating existing ones, but won't that adversely affect performance? Yes, it can. Be sure to do performance testing in your own app. If you need a performance boost, then consider using [Immutable.js][86]. Immutable.js implements [Lists][87], [Stacks][88], [Maps][89], [Sets][90], and other data structures using [persistent data structures][91]. This is the same technique used internally by functional programming languages such as Clojure and Scala.
好,所以我们可以通过创建新的对象来代替修改原来的对象,但是这样不会导致性能损失吗?当然会。确保在你自己的应用中做了性能测试。如果你需要提高性能,可以考虑使用 [Immutable.js][86]。Immutable.js 用[持久的数据结构][91] 实现了[链表][87],[堆栈][88] [映射][89][集合][90]和其他数据结构。使用了和比如 Clojure 和 Scala 的函数式语言中相同的技术。
```
// Use in place of `[]`.
@ -356,15 +340,15 @@ console.log([...set2]); // [1, 2, 3, 4, 5]
[view raw][33][immutable-js-demo.js][34] hosted with ❤ by [GitHub][35]
### Function composition
### 函数组合(不确定是这个叫法
Remember back in high school when you learned something that looked like **(fg)(x)**? Remember thinking, "When am I ever going to use this?" Well, now you are. Ready? **fg** is read "**f composed with g**." There are two equivalent ways of thinking of it, as illustrated by this identity: **(fg)(x) = f(g(x))**. You can either think of **fg** as a single function or as the result of calling function **g** and then taking its output and passing that to **f**. Notice that the functions get applied from right to left—that is, we execute **g**, followed by **f**.
好,你准备好听解答了吗?**fg **读作 **“函数 f 和函数 g 组合”(不确定 没搜到中文资料**。它的定义是 **(fg)(x) = f(g(x))**,你也可以认为 **fg** 是一个单独的函数,它将调用函数 **g** 的结果作为参数传给函数 **f**。注意这些函数是从右向左以此调用的,先执行 **g**,接下来执行 **f**
A couple of important points about function composition:
关于函数组合的几个要点:
1. We can compose any number of functions (we're not limited to two).
1. 我们可以组合任意数量的函数(不仅限于 2 个)。
2. One way to compose functions is simply to take the output from one function and pass it to the next (i.e., **f(g(x))**).
2. 组合函数的一个方式是简单地把一个函数的输出作为下一个函数的输入。(比如 **f(g(x))**)
```
// h(x) = x + 1
@ -392,7 +376,7 @@ console.log(y); // '4'
[view raw][36][function-composition-basic.js][37] hosted with ❤ by [GitHub][38]
There are libraries such as [Ramda][92] and [lodash][93] that provide a more elegant way of composing functions. Instead of simply passing the return value from one function to the next, we can treat function composition in the more mathematical sense. We can create a single composite function made up from the others (i.e., **(fg)(x)**).
[Ramda][92] 和 [lodash][93] 之类的库提供了更优雅的方式来组合函数。我们可以在更多的在数学意义上处理函数组合,而不是简单地将一个函数的返回值传递给下一个函数。我们可以创建一个由这些函数组成的单一复合函数(就是,**(fg)(x)**)。
```
// h(x) = x + 1
@ -424,15 +408,15 @@ console.log(y); // '4'
[view raw][39][function-composition-elegant.js][40] hosted with ❤ by [GitHub][41]
Okay, so we can do function composition in JavaScript. What's the big deal? Well, if you're really onboard with functional programming, then ideally your entire program will be nothing but function composition. There will be no loops (**for**, **for...of**, **for...in**, **while**, **do**) in your code. None (period). But that's impossible, you say! Not so. That leads us to the next two topics: recursion and higher-order functions.
我们可以在 JavaScript 中组合函数。接下来呢?好,如果你已经入门了函数式编程,理想中你的程序将只有函数的组合。代码里没有循环(**for**, **for...of**, **for...in**, **while**, **do**),基本没有。你说但是那不可能。并不是这样。我们下面的两个话题是:递归和高阶函数。
### Recursion
### 递归
Let's say that you would like to implement a function that computes the factorial of a number. Let's recall the definition of factorial from mathematics:
假设你想实现一个计算数字的阶乘的函数。 让我们回顾一下数学中阶乘的定义:
**n! = n * (n-1) * (n-2) * ... * 1**.
That is, **n!** is the product of all the integers from **n** down to **1**. We can write a loop that computes that for us easily enough.
**n!** 是从 **n****1** 的所有整数的乘积。我们可以编写一个循环轻松地计算出结果。
```
function iterativeFactorial(n) {
@ -447,15 +431,13 @@ function iterativeFactorial(n) {
[view raw][42][iterative-factorial.js][43] hosted with ❤ by [GitHub][44]
Notice that both **product** and **i** are repeatedly being reassigned inside the loop. This is a standard procedural approach to solving the problem. How would we solve it using a functional approach? We would need to eliminate the loop and make sure we have no variables being reassigned. Recursion is one of the most powerful tools in the functional programmer's toolbelt. Recursion asks us to break down the overall problem into sub-problems that resemble the overall problem.
注意 **product** 和 **i** 都在循环中被反复重新赋值。这是解决这个问题的标准过程式方法。如何用函数式的方法解决这个问题呢?我们需要消除循环,确保没有变量被重新赋值。递归是函数式程序员的最有力的工具之一。递归需要我们将整体问题分解为类似整体问题的子问题。
Computing the factorial is a perfect example. To compute **n!**, we simply need to take **n** and multiply it by all the smaller integers. That's the same thing as saying: 
计算阶乘是一个很好的例子,为了计算 **n!** 我们需要将 n 乘以所有比它小的正整数。它的意思就相当于:
**n! = n * (n-1)!** 
A-ha! We found a sub-problem to solve **(n-1)!** and it resembles the overall problem **n!**. There's one more thing to take care of: the base case. The base case tells us when to stop the recursion. If we didn't have a base case, then recursion would go on forever. In practice, you'll get a stack overflow error if there are too many recursive calls.
What is the base case for the factorial function? At first you might think that it's when **n == 1**, but due to some [complex math stuff][94], it's when **n == 0**. **0!** is defined to be **1**. With this information in mind, let's write a recursive factorial function.
A-ha我们发现了一个类似于整个问题 **n!** 的子问题来解决 **(n-1)!**。还有一个需要注意的地方就是基础条件。基础条件告诉我们何时停止递归。 如果我们没有基础条件,那么递归将永远持续。 实际上如果有太多的递归调用程序会抛出一个堆栈溢出错误。A-HA
```
function recursiveFactorial(n) {
@ -470,25 +452,25 @@ function recursiveFactorial(n) {
[view raw][45][recursive-factorial.js][46] hosted with ❤ by [GitHub][47]
Okay, so let's compute **recursiveFactorial(20000)**, because... well, why not! When we do, we get this:
然后我们来计算 **recursiveFactorial(20000)** 因为...,为什么不呢?当我们这样做的时候,我们得到了这个结果:
### [stack-overflow.png][48]
![Stack overflow error](https://opensource.com/sites/default/files/u128651/stack-overflow.png "Stack overflow error")
Stack overflow error
堆栈溢出错误
So what's going on here? We got a stack overflow error! It's not because of infinite recursion. We know that we handled the base case (i.e., **n === 0**). It's because the browser has a finite stack and we have exceeded it. Each call to **recursiveFactorial** causes a new frame to be put on the stack. We can visualize the stack as a set of boxes stacked on top of each other. Each time **recursiveFactorial** gets called, a new box is added to the top. The following diagram shows a stylized version of what the stack might look like when computing **recursiveFactorial(3)**. Note that in a real stack, the frame on top would store the memory address of where it should return after executing, but I have chosen to depict the return value using the variable **r**. I did this because JavaScript developers don't normally need to think about memory addresses.
这里发生了什么?我们得到一个堆栈溢出错误!这不是无穷的递归导致的。我们已经处理了基础条件(**n === 0** 的情况)。那是因为浏览器的堆栈大小是有限的,而我们的代码使用了越过了这个大小的堆栈。每次对 **recursiveFactorial** 的调用导致了新的帧被压入堆栈中,就像一个盒子压在另一个盒子上。每当 **recursiveFactorial** 被调用,一个新的盒子被放在最上面。下图展示了在计算 **recursiveFactorial(3)** 时堆栈的样子。注意在真实的堆栈中,堆栈顶部的帧将存储在执行完成后应该返回的内存地址,但是我选择用变量 **r** 来表示返回值,因为 JavaScript 开发者一般不需要考虑内存地址。
### [stack-frames.png][49]
![The stack for recursively calculating 3! (three factorial)](https://opensource.com/sites/default/files/u128651/stack-frames.png "The stack for recursively calculating 3! (three factorial)")
The stack for recursively calculating 3! (three factorial)
递归计算 3! 的堆栈(三次乘法)
You can imagine that the stack for **n = 20000** would be much higher. Is there anything we can do about that? It turns out that, yes, there is something we can do about it. As part of the **ES2015** (aka **ES6**) specification, an optimization was added to address this issue. It's called the  _proper tail calls optimization_  (PTC). It allows the browser to elide, or omit, stack frames if the last thing that the recursive function does is call itself and return the result. Actually, the optimization works for mutually recursive functions as well, but for simplicity we're just going to focus on a single recursive function.
你可能会想象当计算 **n = 20000** 时堆栈会更高。我们可以做些什么优化它吗?当然可以。作为 **ES2015** (又名 **ES6**) 标准的一部分有一个优化用来解决这个问题。它被称作_尾调用优化_。它使得浏览器删除或者忽略堆栈帧当递归函数做的最后一件事是调用自己并返回结果的时候。实际上这个优化对于相互递归函数也是有效的但是为了简单起见我们还是来看单递归函数。
You'll notice in the stack above that after the recursive function call, there is still an additional computation to be made (i.e., **n * r**). That means that the browser cannot optimize it using PTC; however, we can rewrite the function in such a way so that the last step is the recursive call. One trick to doing that is to pass the intermediate result (in this case the **product**) into the function as an argument.
你可能会注意到,在递归函数调用之后,还要进行一次额外的计算(**n * r**)。那意味着浏览器不能通过 PTC 来优化递归;然而,我们可以通过重写函数使最后一步变成递归调用以便优化。一个窍门是将中间结果(在这里是**乘积**)作为参数传递给函数。
```
'use strict';
@ -505,27 +487,27 @@ function factorial(n, product = 1) {
[view raw][50][factorial-tail-recursion.js][51] hosted with ❤ by [GitHub][52]
Let's visualize the optimized stack now when computing **factorial(3)**. As the following diagram shows, in this case the stack never grows beyond two frames. The reason is that we are passing all necessary information (i.e., the **product**) into the recursive function. So, after the **product** has been updated, the browser can throw out that stack frame. You'll notice in this diagram that each time the top frame falls down and becomes the bottom frame, the previous bottom frame gets thrown out. It's no longer needed.
让我们来看看优化后的计算 **factorial(3)** 时的堆栈。如下图所示,堆栈不会增长到超过两层。原因是我们把必要的信息都传到了递归函数中(比如**乘积**)。所以,在**乘积**被更新后,浏览器可以丢弃掉堆栈中原先的帧。你可以在图中看到每次最上面的帧下沉变成了底部的帧,原先底部的帧被丢弃,因为不再需要它了。
### [optimized-stack-frames.png][53]
![The optimized stack for recursively calculating 3! (three factorial) using PTC](https://opensource.com/sites/default/files/u128651/optimized-stack-frames.png "The optimized stack for recursively calculating 3! (three factorial) using PTC")
The optimized stack for recursively calculating 3! (three factorial) using PTC
递归计算 3! 的堆栈(三次乘法)使用 PTC
Now run that in a browser of your choice, and assuming that you ran it in Safari, then you will get the answer, which is **Infinity** (it's a number higher than the maximum representable number in JavaScript). But we didn't get a stack overflow error, so that's good! Now what about all the other browsers? It turns out that Safari is the only browser that has implemented PTC, and it might be the only browser to ever implement it. See the following compatibility table:
现在选一个浏览器运行吧,假设你在使用 Safari你会得到**无穷大**(它是比在 JavaScript 中能表达的最大值更大的数。但是我们没有得到堆栈溢出错误那很不错现在在其他的浏览器中呢怎么样呢Safari 可能现在乃至将来是实现 PTC 的唯一一个浏览器。看看下面的兼容性表格:
### [ptc-compatibility.png][54]
![PTC compatibility](https://opensource.com/sites/default/files/u128651/ptc-compatibility.png "PTC compatibility")
PTC compatibility
PTC 兼容性
Other browsers have put forth a competing standard called [syntactic tail calls][95](STC). "Syntactic" means that you will have to specify via new syntax that you would like the function to participate in the tail-call optimization. Even though there is not widespread browser support yet, it's still a good idea to write your recursive functions so that they are ready for tail-call optimization whenever (and however) it comes.
其他浏览器提出了一种被称作[语法级尾调用][95](STC)的竞争标准。"Syntactic"意味着你需要用新的语法来标识你想要执行尾递归优化的函数。,即使浏览器还没有广泛支持,但是把你的递归函数写成支持尾递归优化的样子还是一个好主意。
### Higher-order functions
### 高阶函数
We already know that JavaScript has first-class functions that can be passed around just like any other value. So, it should come as no surprise that we can pass a function to another function. We can also return a function from a function. Voilà! We have higher-order functions. You're probably already familiar with several higher order functions that exist on the **Array.prototype**. For example, **filter**, **map**, and **reduce**, among others. One way to think of a higher-order function is: It's a function that accepts (what's typically called) a callback function. Let's see an example of using built-in higher-order functions:
我们已经知道 JavaScript 将函数视作一等公民,可以把函数像其他值一样传递。所以,把一个函数传给另一个函数也很常见。我们也可以让函数返回一个函数。就是它!我们有高阶函数。你可能已经很熟悉几个在 **Array.prototype** 中的高阶函数。比如 **filter****map**,和 **reduce** 就在其中。对高阶函数的一种理解是:它是接受(一般会调用)一个回调函数参数的函数。让我们来看看一些内置的高阶函数的例子:
```
const vehicles = [
@ -552,7 +534,7 @@ console.log(averageSUVPrice); // 33399
[view raw][55][built-in-higher-order-functions.js][56] hosted with ❤ by [GitHub][57]
Notice that we are calling methods on an array object, which is characteristic of object-oriented programming. If we wanted to make this a bit more representative of functional programming, we could use functions provided by Ramda or lodash/fp instead. We can also use function composition, which we explored in a previous section. Note that we would need to reverse the order of the functions if we use **R.compose**, since it applies the functions right to left (i.e., bottom to top); however, if we want to apply them left to right (i.e., top to bottom), as in the example above, then we can use **R.pipe**. Both examples are given below using Ramda. Note that Ramda has a **mean** function that can be used instead of **reduce**.
注意我们在一个数组对象上调用其方法,这是面向对象编程的特性。如果我们想要更函数式一些,我们可以用 Rmmda 或者 lodash/fp 提供的函数。注意如果我们使用 **R.compose** 的话,需要倒转函数的顺序,因为它从右向左依次调用函数(从底向上);然而,如果我们想从左向右调用函数就像上面的例子,我们可以用 **R.pipe**。下面两个例子用了 Rmmda。注意 Rmmda 有一个 **mean** 函数用来代替 **reduce**
```
const vehicles = [
@ -590,11 +572,11 @@ console.log(averageSUVPrice2); // 33399
[view raw][58][composing-higher-order-functions.js][59] hosted with ❤ by [GitHub][60]
The advantage of the functional programming approach is that it clearly separates the data (i.e., **vehicles**) from the logic (i.e., the functions **filter**, **map**, and **reduce**). Contrast that with the object-oriented code that blends data and functions in the form of objects with methods.
使用函数式方法的优点是清楚地分开了数据(**车辆**)和逻辑(函数 **filter****map** 和 **reduce**)面向对象的代码相比之下把数据和函数用以方法的对象的形式混合在了一起。
### Currying
### 柯里化
Informally, **currying** is the process of taking a function that accepts **n** arguments and turning it into **n** functions that each accepts a single argument. The **arity** of a function is the number of arguments that it accepts. A function that accepts a single argument is **unary**, two arguments **binary**, three arguments **ternary**, and **n** arguments is **n-ary**. Therefore, we can define currying as the process of taking an **n-ary** function and turning it into **n** unary functions. Let's start with a simple example, a function that takes the dot product of two vectors. Recall from linear algebra that the dot product of two vectors **[a, b, c]** and **[x, y, z]** is equal to **ax + by + cz**.
不规范地说,柯里化是把一个接受 **n** 个参数的函数变成 **n** 个每个接受单个参数的函数的过程。函数的 **arity** 是它接受参数的个数。接受一个参数的函数是 **unary**,两个的是 **binary**,三个的是 **ternary****n**个的是 **n-ary**。那么,我们可以把柯里化定义成将一个 **n-ary** 函数转换成 **n** 个 unary 函数的过程。让我们通过简单的例子开始,一个计算两个向量点积的函数。回忆一下线性代数,两个向量 **[a, b, c]** 和 **[x, y, z]** 的点积是 **ax + by + cz**
```
function dot(vector1, vector2) {
@ -610,7 +592,7 @@ console.log(dot(v1, v2)); // 1(4) + 3(-2) + (-5)(-1) = 4 - 6 + 5 = 3
[view raw][61][dot-product.js][62] hosted with ❤ by [GitHub][63]
The **dot** function is binary since it accepts two arguments; however, we can manually convert it into two unary functions, as the following code example shows. Notice how **curriedDot** is a unary function that accepts a vector and returns another unary function that then accepts the second vector.
**dot** 函数是 binary 因为它接受两个参数;然而我们可以将它手动转换成两个 unary 函数,就像下面的例子。注意 **curriedDot** 是一个 unary 函数,它接受一个向量并返回另一个接受第二个向量的 unary 函数。
```
function curriedDot(vector1) {
@ -630,7 +612,7 @@ console.log(sumElements([4, -2, -1])); // 1
[view raw][64][manual-currying.js][65] hosted with ❤ by [GitHub][66]
Fortunately for us, we don't have to manually convert each one of our functions to a curried form. Libraries including [Ramda][96] and [lodash][97] have functions that will do it for us. In fact, they do a hybrid type of currying, where you can either call the function one argument at a time, or you can continue to pass in all the arguments at once, just like the original.
很幸运,我们不需要把每一个函数都手动转换成柯里化以后的形式。[Ramda][96] 和 [lodash][97] 等库可以为我们做这些工作。实际上,它们是柯里化的混合形式。你既可以每次传递一个参数,也可以像原来一样一次传递所有参数。
```
function dot(vector1, vector2) {
@ -654,7 +636,7 @@ console.log(curriedDot(v1, v2)); // 3
[view raw][67][fancy-currying.js][68] hosted with ❤ by [GitHub][69]
Both Ramda and lodash also allow you to "skip over" an argument and specify it later. They do this using a placeholder. Because taking the dot product is commutative, it won't make a difference in which order we passed the vectors into the function. Let's use a different example to illustrate using a placeholder. Ramda uses a double underscore as its placeholder.
Ramda 和 lodash 都允许你“跳过”一些变量之后再指定它们。它们使用置位符来做这些工作。因为点积的计算可以交换两项。传入向量的顺序不影响结果。让我们换一个例子来阐述如何使用一个置位符。Ramda 使用双下划线作为其置位符。
```
const giveMe3 = R.curry(function(item1, item2, item3) {
@ -677,12 +659,12 @@ console.log(result);
[view raw][70][currying-placeholder.js][71] hosted with ❤ by [GitHub][72]
One final point before we complete the topic of currying, and that is partial application. Partial application and currying often go hand in hand, though they really are separate concepts. A curried function is still a curried function even if it hasn't been given any arguments. Partial application, on the other hand, is when a function has been given some, but not all, of its arguments. Currying is often used to do partial application, but it's not the only way.
在我们结束探讨柯里化之前最后的议题是偏函数应用。偏函数应用和柯里化经常同时出场,尽管它们实际上是不同的概念。一个柯里化的函数还是柯里化的函数,即使没有给它任何参数。偏函数应用,另一方面是仅仅给一个函数传递部分而不是所有参数。柯里化是偏函数应用常用的方法之一,但是不是唯一的。
The JavaScript language has a built-in mechanism for doing partial application without currying. This is done using the [**function.prototype.bind**][98] method. One idiosyncrasy of this method is that it requires you to pass in the value of **this** as the first argument. If you're not doing object-oriented programming, then you can effectively ignore **this** by passing in **null**.
JavaScript 拥有一个内置机制可以不依靠柯里化来偏函数应用。那就是 [**function.prototype.bind**][98] 方法。这个方法的一个特殊之处在于,它要求你将 **this** 作为第一个参数传入。 如果你不进行面向对象编程,那么你可以通过传入 **null** 来忽略 **this**
```
function giveMe3(item1, item2, item3) {
1function giveMe3(item1, item2, item3) {
return `
1: ${item1}
2: ${item2}
@ -703,11 +685,11 @@ console.log(result);
[view raw][73][partial-application-using-bind.js][74] hosted with ❤ by [GitHub][75]
### Wrapping up
### 总结
I hope you enjoyed exploring functional programming in JavaScript with me! For some it may be a completely new programming paradigm, but I hope you will give it a chance. I think you'll find that your programs are easier to read and debug. Immutability will also allow you to take advantage of performance optimizations in Angular and React.
我希望你享受探索 JavaScript 中函数式编程的过程。对一些人来说,它可能是一个全新的编程范式,但我希望你能尝试它。你会发现你的程序更易于阅读和调试。不变性还将允许你优化 Angular 和 React 的性能。
_This article is based on Matt's OpenWest talk, [JavaScript the Good-er Parts][77]. [OpenWest][78] will be held July 12-15, 2017 in Salt Lake City, Utah._
_这篇文章基于 Matt 在 OpenWest 的演讲 [JavaScript the Good-er Parts][77]. [OpenWest][78] ~~将~~在 6/12-15 ,2017 在 Salt Lake City, Utah 举行。_
--------------------------------------------------------------------------------
@ -715,12 +697,14 @@ I hope you enjoyed exploring functional programming in JavaScript with me! For s
Matt Banz - Matt graduated from the University of Utah with a degree in mathematics in May of 2008. One month later he landed a job as a web developer, and he's been loving it ever since! In 2013, he earned a Master of Computer Science degree from North Carolina State University. He has taught courses in web development for LDS Business College and the Davis School District Community Education program. He is currently a Senior Front-End Developer for Motorola Solutions.
Matt Banz - Matt 于 2008 年五月在犹他大学获得了数学学位毕业。一个月后他得到了一份 web 开发者的工作,他从那时起就爱上了它!在 2013 年,他在北卡罗莱纳州立大学获得了计算机科学硕士学位。他在 LDS 商学院和戴维斯学区社区教育计划教授 Web 课程。他现在是就职于 Motorola Solutions 公司的高级前端开发者。
--------------
via: https://opensource.com/article/17/6/functional-javascript
作者:[Matt Banz ][a]
译者:[chenxinlong](https://github.com/chenxinlong)
译者:[trnhoe](https://github.com/trnhoe)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
@ -729,7 +713,7 @@ via: https://opensource.com/article/17/6/functional-javascript
[1]:https://opensource.com/tags/python?src=programming_resource_menu1
[2]:https://opensource.com/tags/javascript?src=programming_resource_menu2
[3]:https://opensource.com/tags/perl?src=programming_resource_menu3
[4]:https://developers.redhat.com/?intcmp=7016000000127cYAAQ&src=programming_resource_menu4
[4]:https://developers.redhat.com/?intcmp=7016000000127cYAAQ&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;src=programming_resource_menu4
[5]:https://gist.github.com/battmanz/62fa0a78841aa0fe29d99e80ba8db2b1/raw/fd586c5da7c936235a6d99b11cb80c9c67e4deaf/pure-function-example.js
[6]:https://gist.github.com/battmanz/62fa0a78841aa0fe29d99e80ba8db2b1#file-pure-function-example-js
[7]:https://github.com/