【23.5.3】纯函数、一等公民函数、不可变数据、持久化数据结构、immerJs、immutableJs

30 阅读3分钟

一.纯函数

定义:

纯函数是指在相同的输入下总是返回相同的输出,且没有副作用(不修改参数,不修改全局变量等)的函数。

特点:

  1. 相同的输入总是返回相同的输出
  2. 没有副作用
  3. 可缓存,提高代码性能(在遇到大运算代码时可以将结果缓存,如果后面入参一样可以直接使用结果)
  4. 易于进行代码测试

优点:

  1. 提高代码的可读性和可维护性
  2. 可以避免一些常见问题,如并发问题和数据共享问题
  3. 使代码更加模块化

应用场景:

  1. 数组的转换和过滤
  2. 数组和对象的操作
  3. 纯函数可以作为其他函数的参数,如高阶函数的参数

例子:

function add(a,b){
    return a+b;
}
function multiply(a,b){
    return a*b;
}
function filter(arr,fn){
    return arr.filter(fn);
}
function compose(f,g){
    return function(x){
       return f(g(x));
    };
}

二. 副作用

定义:

函数除了计算之外,还对它的执行上下文和执行宿主等外部环境造成了一些其他的影响,这些影响就是副作用。比如函数中做请求、改变全局上下文中的某个变量等等

三. 一等公民函数

定义:

  1. 可以被当作参数传递给其他函数
  2. 可以赋值给变量
  3. 可以作为另外一个函数的返回值

四.不可变数据

不可变数据是保障函数纯度的安全线。因为纯函数要求同样的输出会对应着同样的输入,如果出现如下的情况则改函数就不再

const param = {width: 100, height: 100};
function calcArea(obj) {
    return obj.width * obj.height
}
console.log(calcArea(param)) // 10000
const params = param
params.height = 10
console.log(param === params) // true
console.log(calcArea(param)) // 1000

可以看到params经过param赋值后,然后又改变了height的值,但是这个时候params === param仍然为true,但是计算的结果却不一样了,这里涉及到了js数据类型的值类型引用类型,值类型的拷贝是在内存中重新开辟一块区域来保存数据,而引用类型的拷贝则是将指向数据的地址拷贝了一份,但是其指向还是没有变化的。导致修改拷贝之后的引用之后,内存中保存的数据也会改变,这就导致了数据的可变性。
可变数据的危害:

将函数的计算结果变得难以预测(说不定就在程序中的某个地方被改变了),这就违背了纯函数的定义

解决办法:

控制数据的变化,确保所有的变化都在可预期的范围内发生。可以使用拷贝来复制一份数据,有对数据操作的计算可以在拷贝的数据上进行,这样就不会对原有的数据造成影响,从而不会影响其他函数的纯度

五.持久化数据结构

虽然拷贝是解决数据可变的一种方案,但是在有些情况下并不适用,比如当拷贝的数据太大以及用的地方很多时,这个时候多次拷贝数据就会产生冗余,占用更多的内存。这种情况下拷贝并不是一个好的方案。

5.1 ImmerJs

5.2 ImmutableJs

immutable是FaceBook团队是一个实现数据持久化机构的库。 他的原理是共享未改变的数据,已修改的数据重新创建一块区域来保存 ,这样就避免了重复拷贝数据的冗余问题

使用例子:

// 引入 immutable 库里的 Map 对象,它用于创建对象 
import { Map } from 'immutable' 
// 初始化一个对象 baseMap 
const originData = Map({ name: 'xiuyan', hobby: 'coding', age: 666 }) 
// 使用 immutable 暴露的 Api 来修改 baseMap 的内容 
const mutatedData = originData.set({ age: 66.6 }) 
// 我们会发现修改 baseMap 后将会返回一个新的对象,这个对象的引用和 baseMap 是不同的 
console.log('originData === mutatedData', originData === mutatedData)