什么是函数式编程?它跟纯函数的联系是什么?
函数式编程(Functional Programming,简称FP)是一种编程范式,它强调使用纯函数(Pure Functions)来解决计算问题。纯函数在函数式编程中扮演着关键角色,因为它们具有特定的属性和行为,使得函数式编程的原则和优点成为可能。
以下是函数式编程和纯函数之间的联系:
-
纯函数是函数式编程的基石:函数式编程的核心思想是使用纯函数来构建程序。纯函数是没有副作用的函数,其输出仅依赖于输入参数,不依赖于外部状态或变量。这种特性使得纯函数在函数式编程中成为可重用和可组合的构建块。
-
可缓存性(Cacheable):函数式编程强调数据不可变性,这意味着一旦数据被创建,就不能再被修改。纯函数与不可变性相辅相成。因为纯函数不修改输入,所以它们天然支持不可变性。在函数式编程中,不可变性有助于避免共享状态和副作用。
-
无状态性:纯函数没有内部状态,它们不维护任何外部状态。这与函数式编程的无状态原则相符,即程序的行为不依赖于历史状态,仅依赖于输入。
-
可测试性:纯函数易于测试,因为它们的行为完全取决于输入参数。在测试中,您可以提供不同的输入并验证输出是否符合预期,而无需担心外部状态的影响。
-
可组合性:纯函数具有良好的可组合性,因为它们不产生副作用。您可以将纯函数组合成更复杂的功能,而不会导致意外的行为。
-
引用透明性:纯函数是引用透明的,这意味着您可以用函数的结果替换函数调用,而不会改变程序的行为。这种特性有助于推导程序的性质和进行优化。
可缓存性(Cacheable)
纯函数的可缓存性是指,纯函数总能够根据输入来做缓存。实现缓存的一种典型方式是 memoize 技术。原理上只用把参数和对应的结果数据存到一个对象中,调用时,判断参数对应的数据是否存在,存在就返回对应的结果数据。
示例如下:
js
var memoize = function(f) {
var cache = {};
return function() {
var arg_str = JSON.stringify(arguments);
cache[arg_str] = cache[arg_str] || f.apply(f, arguments);
return cache[arg_str];
};
};
var squareNumber = memoize(function(x){
console.log('计算',x)
return x*x;
});
var printWrap = function(x){return console.log(squareNumber(x))}
printWrap(4)
//=> 16
printWrap(4); // 从缓存中读取输入值为 4 的结果
//=> 16
printWrap(5);
//=> 25
printWrap(5); // 从缓存中读取输入值为 5 的结果
//=> 25
打印的结果:
可以看到相同输入的值只被计算了一次。
playground: playcode.io/1603378
什么是纯函数
纯函数的概念。
纯函数是这样一种函数,即相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用。
比如 slice
和 splice
,这两个函数都可以作为切割数组使用。但是他们各自实现的方式却大不相同 slice
符合纯 函数的定义是因为对相同的输入它保证能返回相同的输出。而 splice
却会改变调用它的那个数组,然后再返回;这就会产生可观察到的副作用,即这个数组永久地改变了
slice
创建一个新的数组,不会修改原始数组,根据指定的索引截取出一段连续的元素。
splice
修改原始数组,从指定的索引位置删除或添加元素,返回已删除的元素组成的新数组。
js
var xs = [1,2,3,4,5];
// 纯的
xs.slice(0,3);
//=> [1,2,3]
xs.slice(0,3);
//=> [1,2,3]
xs.slice(0,3);
//=> [1,2,3]
// 不纯的
xs.splice(0,3);
//=> [1,2,3]
xs.splice(0,3);
//=> [4,5]
xs.splice(0,3);
//=> []
总结
总之,函数式编程侧重于使用纯函数来构建程序,这些函数不依赖于外部状态、不产生副作用,并且易于测试和组合。这些特性使函数式编程具有可维护性、可测试性和可理解性的优点,并且有助于编写更安全和健壮的代码。纯函数是函数式编程的基本构建块,使函数式编程成为一种强大的编程范式。