Open Genzhen opened 3 years ago
每日一题会在下午四点在交流群集中讨论,五点小程序中更新答案 欢迎大家在下方发表自己的优质见解 二维码加载失败可点击 小程序二维码
纯函数是函数式编程的基础。
纯函数是这样一种函数,即相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用,也不依赖外部环境的状态。
他的重点在于相同的输入,永远会得到相同的输出
“作用”我们可以理解为一切除结果计算之外发生的事情。
副作用是在计算结果的过程中,系统状态的一种变化,或者与外部世界进行的可观察的交互。
副作用可能包含,但不限于:
概括来讲,只要是跟函数外部环境发生的交互就都是副作用。函数式编程的哲学就是假定副作用是造成不正当行为的主要原因。
先看个不纯的反面典型
let a = 1; function add(b) { return a + b; } console.log(add(2)); //3
上面代码中,add(2),是不是永远返回 3,显然是不是的。假如我们修改了 a 的值,就会影响 add 函数的输出。即函数 add 其实是依赖外部状态的。
如果想改成纯的函数,可以这样改:
function add(b) { let a = 1; return a + b; } console.log(add(2)); //3
这样对于任何输入参数,都有与之对应的唯一输出参数了,该函数就符合纯函数的特点了。
先来看个反面典型:
const user = { name: "yideng", }; let isValid = false; function check(user) { if (user.name.length > 4) { isValid = true; } }
可以看到,执行函数的时候会修改到 isValid 的值,这样就存在副作用了,这个函数的运行,修改了外部的状态。
那可以怎么处理移除这个副作用呢?其实不需要修改外部的 isValid 变量,我们只需要在函数中将验证的结果 return 出来:
const user = { name: "yideng", }; function check(user) { return user.name.length > 4; } const isValid = check(user);
这样 check 函数就不会修改任何外部的状态了~
纯函数可以根据输入来做缓存。实现缓存的是一种叫作 memorize 的技术。
看下 vue 源码中的一段代码:
/** * Create a cached version of a pure function. * 只适用于缓存 接收一个字符串为参数的 fn */ export function cached(fn) { const cache = Object.create(null); return function cachedFn(str) { const hit = cache[str]; return hit || (cache[str] = fn(str)); }; } /** * Capitalize a string. */ export const capitalize = cached((str) => { return str.charAt(0).toUpperCase() + str.slice(1); });
capitalize 即为缓存后的函数,如果多次调用就会返回缓存后的值,从而节省计算资源,而这一切的前提都建立在传入 cached 中的那个函数为纯函数的基础上。
由于纯函数是自给自足的,它需要的东西都在输入参数中已经声明,所以它可以任意移植到任何地方。
函数让测试更加容易。我们不需要伪造一个“真实的”支付网关,或者每一次测试之前都要配置、之后都要断言状态(assert the state)。只需简单地给函数一个输入,然后断言输出就好了。
看个反面的例子,使用上边不纯的 add 方法来做单元测试:
// jest 语法 describe("add", function () { it("add", function () { expect(add("2")).toEqual(3); }); });
如果我们修改了 a 为 3,上面的测试就会失败了。
它应始终返回相同的值。不管调用该函数多少次,无论今天、明天还是将来某个时候调用它。 自包含(不使用全局变量)。 它不应修改程序的状态或引起副作用(修改全局变量
扫描下方二维码,收藏关注,及时获取答案以及详细解析,同时可解锁800+道前端面试题。
一、概念
1.1 什么是纯函数
纯函数是函数式编程的基础。
纯函数是这样一种函数,即相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用,也不依赖外部环境的状态。
他的重点在于相同的输入,永远会得到相同的输出
1.2 什么是副作用
“作用”我们可以理解为一切除结果计算之外发生的事情。
副作用是在计算结果的过程中,系统状态的一种变化,或者与外部世界进行的可观察的交互。
副作用可能包含,但不限于:
概括来讲,只要是跟函数外部环境发生的交互就都是副作用。函数式编程的哲学就是假定副作用是造成不正当行为的主要原因。
二、纯函数两个特点
2.1 相同的输入得到相同的输出
先看个不纯的反面典型
上面代码中,add(2),是不是永远返回 3,显然是不是的。假如我们修改了 a 的值,就会影响 add 函数的输出。即函数 add 其实是依赖外部状态的。
如果想改成纯的函数,可以这样改:
这样对于任何输入参数,都有与之对应的唯一输出参数了,该函数就符合纯函数的特点了。
2.2 没有副作用
先来看个反面典型:
可以看到,执行函数的时候会修改到 isValid 的值,这样就存在副作用了,这个函数的运行,修改了外部的状态。
那可以怎么处理移除这个副作用呢?其实不需要修改外部的 isValid 变量,我们只需要在函数中将验证的结果 return 出来:
这样 check 函数就不会修改任何外部的状态了~
三、为什么要使用纯函数
3.1 可缓存性
纯函数可以根据输入来做缓存。实现缓存的是一种叫作 memorize 的技术。
看下 vue 源码中的一段代码:
capitalize 即为缓存后的函数,如果多次调用就会返回缓存后的值,从而节省计算资源,而这一切的前提都建立在传入 cached 中的那个函数为纯函数的基础上。
3.2 可移植性/自文档化(Portable / Self-Documenting)
由于纯函数是自给自足的,它需要的东西都在输入参数中已经声明,所以它可以任意移植到任何地方。
3.3 可测试性
函数让测试更加容易。我们不需要伪造一个“真实的”支付网关,或者每一次测试之前都要配置、之后都要断言状态(assert the state)。只需简单地给函数一个输入,然后断言输出就好了。
看个反面的例子,使用上边不纯的 add 方法来做单元测试:
如果我们修改了 a 为 3,上面的测试就会失败了。