函数式编程 -- 纯函数
什么是纯函数?
纯函数:相同的输入永远会得到相同的输出,而且没有任何可观察的副作用
// 纯函数slice和不纯函数splice
let array=[1,3,6,8]
//slice不改原数组,第次输出结果是一样的,是纯函数
console.log(array.slice(0,3))
console.log(array.slice(0,3))
console.log(array.slice(0,3))
// 输出:
// [1,3,6]
// [1,3,6]
// [1,3,6]
//splice改变了原数组,每次输出结果不一样,不是纯函数
console.log(array.splice(0,3))
console.log(array.splice(0,3))
console.log(array.splice(0,3))
// 输出:
// [1,3,6]
// [8]
// []
纯函数的好处
-
因为纯函数每次都能够得到相同的结果,所以可以把结果缓存起来
-
在lodash中有记忆函数,可以缓存结果
const require('lodash') function getArea(r){ console.log(r) return Math.PI*r*r } let getAreaWithMemory=__.memoize(getArea) console.log(getAreaWithMemory(4)) console.log(getAreaWithMemory(4)) console.log(getAreaWithMemory(4)) // 输出: // 4 // 50.26548245743669 // 50.26548245743669 // 50.26548245743669
-
从结果可以看出,只有第一次输出了4,其它再次都是直接输出的缓存结果
-
具体的memoize方法是怎么实现的,现在来模拟一下
// 模拟 memoize 方法 function memoize(f){ let cache = {} return function(){ let key = JSON.stringify(arguments) cache[key] = cache[key] || f.apply(f,arguments) return cache[key] } } // 测试 let getAreaWithMemory = memoize(getArea) console.log(getAreaWithMemory(4)) console.log(getAreaWithMemory(4)) console.log(getAreaWithMemory(4)) // 输出: // 4 // 50.26548245743669 // 50.26548245743669 // 50.26548245743669
-
-
纯函数让测试变得更方便,因为其没有副作用,不用考虑结果之外的影响
-
纯函数不需要访问共享的内存数据,所有在并行环境中可以任意运行纯函数(es6以后新增了Web Worker,Web Worker可以开启新的线程)
函数的副作用
-
什么是函数的副作用?
// 不纯的函数 let mini = 18 function checkAge(age){ // 这里函数依赖外部变量mini,当外部变量mini发生改变时, // 会对函数checkAge的结果产生影响,无法保证相同的输入得到相同的输出, // 所以此函数不是纯函数, // 由于外部产生的影响就是此函数的副作用 return age >= mini }
-
函数的副作用的来源
- 配置文件
- 数据库
- 获取用户的输入
- ...
所有外部交互都有可能带来副作用,副作用会使方法通用性降低而变得不易扩展或重用,同时出会为程序带来安全隐患和不确定性,副作用不是可以完全避免的,我们在开发过程应该尽可能的把它控制在可控范围内