简介
"纯函数 "是那些一开始可能让人望而生畏的术语之一,但这个概念其实很简单。在这篇文章中,我将快速定义什么是纯函数以及为什么它们是好的。
两个标准
要被认为是纯函数,一个函数必须满足两个标准:它必须有(1)相同的输入有相同的输出;(2)没有副作用。
让我们更深入地了解这些标准。
相同的输入有相同的输出
让我们首先考虑一个对相同的输入没有相同输出的函数:下面的greet 函数。
let greeting = 'Hello';
function greet(name) {
return greeting + ' ' + name;
}
console.log(greet('Paul'));
// Hello Paul
greet 我们在这里看到,即使该函数的输入name 保持不变,该函数的输出也会发生变化(我们所要做的就是改变greeting 的变量值)。
我们怎样才能使输入相同的情况下输出也相同呢?这很简单,只要确保greeting 也是函数的一个参数就可以了。
function greet(greeting, name) {
return greeting + ' ' + name;
}
console.log(greet('Howdy', 'Paul'));
// Howdy Paul
现在,除非我们改变它的一个输入参数,否则我们没有办法使greet 函数返回不同的结果。
没有副作用
副作用是指函数改变了函数范围之外的东西。再一次,让我们看看一个违反 "无副作用 "规则的函数的例子。
const user = {
username: "bob1234";
}
let isValid = false;
function validate(user) {
if (user.username.length > 4) {
isValid = true;
}
}
我们可以看到,我们显然是在改变isValid 这个变量,而这个变量是在validate 函数的范围之外。(注意:如果你的函数没有返回任何东西,那就强烈表明它可能有副作用!)。
那么,我们如何消除这种副作用呢?我们可以从函数本身返回用户是否有效,而不是改变一个外部isValid 变量。
const user = {
username: "bob1234";
}
function validate(user) {
return user.username.length > 4;
}
const isValid = validate(user);
就这样,我们的validate 函数不再改变其范围之外的任何东西。
为什么纯函数是好的?
你可能有一些直觉,认为这些纯函数的概念是好的,尤其是当你亲身经历过为什么它们是坏的。你越能封装逻辑,就越容易测试,也越容易改变而不用担心改变会影响什么。
让我们考虑测试我们的greet 函数。在它的初始形式下,我们可以做出以下断言。
describe('greet', function () {
it('shows a greeting', function () {
expect(greet('Jane')).toEqual('Hello Jane');
});
});
然而,如果我们把greeting 变量改为 "Hi",我们的测试就会失败!这不应该发生。这种情况不应该发生;我们的函数工作正常,但它失败了,因为它依赖于一个超出其范围的变量。当我们把greeting 作为greet 函数的参数时,这个问题就不存在了,因为我们需要使用该函数的所有信息都必须在测试中作为参数提供。
现在让我们考虑一下我们的用户验证例子。我们甚至如何去测试它呢?可能很难断言函数外部的变量被改变。此外,如果我们把isValid 变量的默认值改为true ,函数就会失败。让这个外部变量发生变化,感觉肯定不对。
总结
我希望这封邮件能让我们了解什么是纯函数,以及为什么它们是有用的!