ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] ## 实例 纯函数 ``` 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); //=> [] ``` ## 有哪些副作用 * 更改文件系统 * 往数据库插入记录 * 发送一个 http 请求 * 可变数据 * 打印/log * 获取用户输入 * DOM 查询 * 访问系统状态 概括来讲,只要是跟函数外部环境发生的交互就都是副作用——这一点可能会让你怀疑无副作用编程的可行性。函数式编程的哲学就是假定副作用是造成不正当行为的主要原因 这并不是说,要禁止使用一切副作用,而是说,要让它们在可控的范围内发生 . ## 纯函数好处 函数是不同数值之间的特殊关系:每一个输入值返回且只返回一个输出值,如输入相同的x值,都只是返回相同的值y ### 可缓存性(Cacheable) ``` const memoize=function (f) { const cache = {}; return function () { const arg = JSON.stringify(arguments); const res =cache[arg]|| f.apply(f,arguments); cache.arg= res return res } } // 需要缓存的函数 const squareNumber = memoize(function(x){ return x*x; }); const square = memoize(squareNumber) console.log(square(1)); // 1 console.log(square(2)); // 4 console.log(square(1)); // 1 ``` 延迟执行的方式把**不纯的函数转换为纯函数** ``` var pureHttpCall = memoize(function(url, params){ return function() { return $.getJSON(url, params); } }); ``` - 当调用它的时候才会发请求。这个函数之所以有资格成为纯函数,是因为它总是会根据相同的输入返回相同的输出:给定了`url`和`params`之后,它就只会返回同一个发送 http 请求的函数 - 我们的`memoize`函数工作起来没有任何问题,虽然它缓存的并不是 http 请求所返回的结果,而是生成的函数。 ### 可移植性/自文档化(Portable / Self-Documenting) 纯函数是完全自给自足的 ``` // 不纯的 var signUp = function(attrs) { var user = saveUser(attrs); welcomeUser(user); }; var saveUser = function(attrs) { var user = Db.save(attrs); ... }; var welcomeUser = function(user) { Email(user, ...); ... }; // 纯的 var signUp = function(Db, Email, attrs) { return function() { var user = saveUser(Db, attrs); welcomeUser(Email, user); }; }; var saveUser = function(Db, attrs) { ... }; var welcomeUser = function(Email, user) { ... }; ``` 在 JavaScript 的设定中,可移植性可以意味着把函数序列化(serializing)并通过 socket 发送。也可以意味着代码能够在 web workers 中运行。总之,可移植性是一个非常强大的特性 ### 可测试性(Testable) 纯函数让测试更加容易。我们不需要伪造一个“真实的”支付网关,或者每一次测试之前都要配置、之后都要断言状态(assert the state)。只需简单地给函数一个输入,然后断言输出就好了 ### 合理性(Reasonable) 很多人相信使用纯函数最大的好处是*引用透明性*(referential transparency ### 并行代码 最后一点,也是**决定性**的一点:我们可以并行运行任意纯函数。因为纯函数根本不需要访问共享的内存,而且根据其定义,纯函数也不会因副作用而进入竞争态(race condition)。 并行代码在服务端 js 环境以及使用了 web worker 的浏览器那里是非常容易实现的,因为它们使用了线程(thread)。不过出于对非纯函数复杂度的考虑,当前主流观点还是避免使用这种并行。