关于副作用,见《JavaScript函数式编程之副作用》
JavaScript函数式编程之深入理解纯函数
更多相关内容见博客 github.com/zhuanyongxi…
纯函数是函数式编程的基础,需要重点理解。纯函数的作用,可以看《JavaScript函数式编程之为什么要函数式编程(非严谨技术层面的扯淡)》。
纯函数的概念:
纯函数是这样一种函数,即相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用。
他的重点在于“相同的输入,永远会得到相同的输出”,后面所说的副作用也是为了满足这一点。
在详细说明纯函数之前,先讲两个其他的概念:可变数据类型和不可变数据类型。
我们知道,在JavaScript中,基本数据类型都是不可变的,他们只能被替换,不能被修改。例如当我们在对字符串进行操作的时候,我们并不能改变这个字符串本身。
var str = 'I am hero'; console.log(str.toUpperCase()); // "I AM HERO" console.log(str); //"I am hero"
我们能做的只有把返回的新字符串重新赋值给变量。
var str = 'I am hero'; str = str.toUpperCase(); // "I AM HERO"
而引用数据类型都是可变的,存在变量中的仅仅就是一个地址。对于可变特性,facebook的immutable.js做了针对性的强化处理,此外还有clojurescript这样更加彻底的方式。
为什么要说这两个概念呢?
先不说在JS运行的系统环境中可能会产生副作用,单单看这些可变的数据类型,就会增加我们写纯函数的难度,要十分注意,个别情况我们只能选择接受。
这样的话,在JS中,我们不妨把纯函数换一种方式理解,不要把它当做一个只有“完全满足要求”和“不满足要求”的标准,而要把它想象成一个范围,在这里有高低不同程度的纯函数。
如何理解“相同的输入,永远会得到相同的输出”
文章开头的纯函数的概念中的“永远”可能会让你疑惑,要把它放在词法作用域中考虑,也就是说不考虑再下次执行之前修改常量这一类的情况。
例一
var a = 5; function A(b) { return a + b; } A(5);
A函数是一个纯函数吗?显然非常不纯,在程序执行的过程中,变量a很容易被修改,这就会导致每次调用A(5)
的返回值改变。
例二
对例一稍作修改
const a = 5; function A(b) { return a + b; } A(5);
这是纯函数,确定的输入,确定的输出。
例三
把例二数字常量换成对象
const obj = {id: 5}; function A(_obj) { return _obj.id; } A(obj);
函数A基本上是纯函数,为什么说是“基本上”?因为有极端情况如下
var obj = { get id() { return Math.random(); } }
注意,obj在传进函数A之前是确定的,getter
是在取值的时候才会执行,但是返回的结果是不确定的,所以这个时候函数A就不是纯函数了。随机数和Date
都会造成函数不纯,使用的时候要注意。
除此之外,由于对象是可变数据类型,我们在每次输入变量obj
到函数A中时,并不具有绝对的自信会返回确定的值。可对于函数A来说,它只关心传进来的数据是什么,而对于那个数据来说,只要不是上面的极端情况,返回的是确定的值。
例四
const obj = {a: 5}; function A(b) { return obj.a + b; } A(5);
这个很明显很不纯,同例一,注意与例三的区别。
例五
对例四稍作修改
const obj = Object.freeze({a: 5}); function A(b) { return obj.a + b; } A(5);
这样就纯多了,可是需要注意的是,
Object.freeze()
这个方法无法冻结嵌套的对象,例如const obj = Object.freeze({a: {a: 5}}); obj.a.a = 10; function A(b) { return obj.a.a + b; } console.log(A(5)); // 15,不纯
例六
function foo(x) { return bar(x); } function bar(y) { return y + 1; } foo(1);
都纯。
例七
function A(a) { return function(b) { return a + b; } } var B = A(5);
函数A和函数B是纯函数吗?首先来看函数A,每次输入一个参数,都会得到一个用这个参数组成的函数,得到的函数是固定的,所以函数A是纯函数;再来看函数B虽然看起来好像使用了一个自己外部的变量a,而且这个变量a可能会经常改变,可是,函数B一定要在调用了函数A之后才能得到,并且得到了之后,变量a是无法改变的,这就很纯了。
即便在返回函数B之前修改了a,例如
例八
function A(a) { a = 0; return function(b) { return a + b; } } var B = A(5);
结论也是一样的。
可如果这样写
例九
function A(a) { return function(b) { return a = a + b; } } var B = A(5);
原文发布时间为:2018年06月08日
原文作者:砖用冰西瓜
本文来源: 掘金 如需转载请联系原作者
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Java学习(13)--包/修饰符
一、包 概述:其实就是文件夹,不允许包名重复,一般是域名反写 作用:对类进行分类管理 操作:增删改查 分类:1.按模块 2.按功能 二、修饰符 (1)分类: 权限修饰符: private(私有的;只能在内部访问), 默认(default;包访问权限) , protected(受保护的;子类访问权限),public(公共的;所有的都可以访问) 状态修饰符: static,final 抽象修饰符: abstract 权限修饰符 (2)常见的类及其组成的修饰 类:默认(default) ,public,final,abstract 常用的: public 成员变量:private, 默认(default) ,protected,public,static,final 常用的: private 构造方法:private, 默认(default) ,protected,public 常用的: public 成员方法:private, 默认(default) ,protected,public,static,final,abstract 常用的: public (3)另外比较常见的: publ...
- 下一篇
Django之路——2 Django的安装
Django的安装分为两种方式,一种是命令行安装,另外一种是pycharm安装。在这里只说一种在命令行里面安装的 1.命令行安装 这个自不必多说,直接上干货,如果遇到pip版本过低,安装失败的,请自自行按照命令行的提示更新pip版本。 由于我已经安装过了 所以显示我已经安装了 目前最新版本是2.0.6版本。安装之后我们还要做一件事就是把Django加入环境变量: 找到图上的这个Django-admin.exe(应用程序),这样就说明我们安装成功了,然后要做的就是把这个加入环境变量,这样方便以后再cmd命令行里面直接敲命令。 2.既然我们安装成功了,那我们就来新建一个Django的项目: 这个mysite是项目名称,这里要注意一点,很多小白在新建一个项目的时候不知道自己的项目放在什么,你当前所在的位置就是你项目所在的地方。 当前目录下会生成mysite的工程,目录结构如下: manage.py-----Django项目里面的工具,通过它可以调用djangoshell和数据库等。 settings.py----包含了项目的默认设置,包括数据库信息,调试标志以及其他一些工作的变量。 u...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS6,CentOS7官方镜像安装Oracle11G
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- CentOS关闭SELinux安全模块
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- Hadoop3单机部署,实现最简伪集群
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- SpringBoot2全家桶,快速入门学习开发网站教程