JavaScript函数式编程之深刻理解纯函数

更多相关内容见博客 https://github.com/zhuanyongxigua/blog
纯函数是函数式编程的基础,须要重点理解。javascript

纯函数的概念:java

纯函数是这样一种函数,即相同的输入,永远会获得相同的输出,并且没有任何可观察的反作用。

他的重点在于“相同的输入,永远会获得相同的输出”,后面所说的反作用也是为了知足这一点。git

在详细说明纯函数以前,先讲两个其余的概念:可变数据类型和不可变数据类型。github

咱们知道,在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这样更加完全的方式。dom

为何我要说这两个概念呢?ide

先不说在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);

关于反作用,见《JavaScript函数式编程之反作用》

参考资料:

相关文章
相关标签/搜索