如何理解js中的纯函数

771 阅读3分钟

1.什么是纯函数 ?

含义:相同的输入,总是会得到相同的输出,并且在执行过程中没有任何副作用。

2.怎么理解相同的输入总是会的到相同的输出?

例子1 :slice和splice的比较

const arr = [1, 2, 3, 4, 5]
arr.slice(0, 3) //[1, 2, 3]
arr.slice(0, 3) //[1, 2, 3]
arr.splice(0, 3) //[1, 2, 3]
arr.splice(0, 3) //[4,5]
  • 上面例子中slice每次传入的参数相同返回值也相同,因此是纯函数。slice返回截取后的数组,不会改变原数组
  • 而splice每次传入的参数相同但是返回值不同,因此不是纯函数。splice返回截取后的数组,会改变原数组,因此每次的返回结果都会变化

例子2

 // 纯的
    function sum(a, b) {
        return a + b;
    }
     const res1 = sum(1, 2); //3
     const res2 = sum(1, 2); //3
  // 不纯的,修改了自己的入参? fix可以像我下面这样理解么,传入了同一个account(同一个引用地址,内容不同),但是返回值不一样
    function withdraw(account, amount) {
        account.total -= amount;
        return account;
    }
    const account = {
        total: 100
    }
    const res1 = withdraw(account, 10) //{total:90}
    account.total = 20 
    const res2 = withdraw(account, 10) //{total:10}

再来看一个例子吧

// 不纯的 checkAge 的结果将取决于 minimum 这个可变变量的值。换句话说,它取决于系统状态(system state)
var minimum = 18;

var checkAge = function(age) {
    return age >= minimum;
};
var isGrown = checkAge(18) //true
var minimum = 20
var isGrown = checkAge(18) //false
  // 纯的 
// 第一种方式在函数内部定义minimum变量,不受外部环境影响
var checkAge = function(age) {
    var minimum = 18;
    return age >= minimum;
};
var isGrown = checkAge(18) //true
var isGrown = checkAge(18) //true


// 第二种方式 使minimum成为一个不可变(immutable)对象
var immutableState = Object.freeze({
    minimum: 18
});

var checkAge = function(age) {
    return age >= immutableState.minimum;
};
var isGrown = checkAge(18) //true
immutableState.minimum = 20
console.log('immutableState', immutableState)
var isGrown = checkAge(18) //true

3 什么是副作用?

  • “作用”我们可以理解为一切除计算结果之外发生的事情。“作用”本身并没什么坏处,“副作用”的关键部分在于“副”。就像一潭死水中的“水”本身并不是幼虫的培养器,“死”才是生成虫群的原因。同理,副作用中的“副”是滋生 bug 的温床。

  • 副作用是在计算结果的过程中,系统状态的一种变化,或者与外部世界进行的可观察的交互。fix 怎么理解?

  • 概括来讲,只要是跟函数外部环境发生的交互就都是副作用

  • 副作用可能包含,但不限于:

    更改文件系统
    往数据库插入记录
    发送一个 http 请求
    可变数据
    打印/log
    获取用户输入
    DOM 查询
    访问系统状态
    

4 纯函数的好处?

  • 更容易进行测试,结果只依赖输入,测试时可以确保输出稳定
  • 更容易维护和重构,我们可以写出质量更高的代码
  • 更容易调用,我们不用担心函数会有什么副作用
  • 结果可以缓存,因为相同的输入总是会得到相同的输出

缓存性

 // 简单实现缓存的一个函数 fix怎么理解
    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) {
        return x * x;
    });
    squareNumber(4); //16
    squareNumber(4); // 从缓存中读取输入值为 4 的结果
    squareNumber(5); //25
    squareNumber(5); // 从缓存中读取输入值为 5 的结果

5纯函数应用的经典案例有哪些?

  • 数组的基本方法 数组的很多基本方法都是纯函数,例如map,forEach,filter,reduce等等。

  • react和vue中的props的只读性和props的单向数据流 所有 React 组件都必须像纯函数一样保护它们的 props 不被更改。 react官方文档

  • redux中的reducer Reducer 只是一些纯函数,它接收先前的 state 和 action,并返回新的 state。 Redux官方文档

  • Lodash