immutable与React 我的一点浅见

233 阅读3分钟

刚起这个题目的时候,我就在想这篇肯定很难写,不仅因为担心自己没有理解那么深刻,还因为我对函数式编程其实好想也没有那么多的好感,很多时候我觉得oop(面向对象)也非常优秀啊。对于我而言,我在写这篇文章时,对immutable更多停留在react 中,因为 react 不能识别深层次state,props 的变化,为了避免出现bug迫使程序员门用immutable,每次生成新的数据来避免side-effect。不然你不知道你改了state为啥UI没有变呢?就很突然~

我在学习react中,包括现在react社区都在说:
immutable:一个不可变变量永远不能被改变。要更新它的值,你需要创建一个新的变量
UI = Fn(state)

从这个式子中,我们发现我们熟知的组件化是不是就是函数化,由无数的Fn生成的不同组件。 在react中,其实state 的语义就挺immutable,仿佛在告诉你,用react 就一定要用immutable啊。所以在react 刚兴起那几年,出现很多的immutable的库,比较有代表的有:immutable.js , Mori, immer。我们知道js的深拷贝一直是js的一个课题,从js语法本身我们很难检测,一个对象如果在较深层次节点改变了,这个对象是否发生了变化。社区解决的方案基本是都是:tree + share 的方式解决的。

1. tree + share 实现immutable

看下面的图,我们很容易知道这样进行路径拷贝,旧的字节点我们可以直接引用,我们新增根节点和其余字节点就生成了一个新的数据,是不是很酷,确实very cool~

image.png

它的优点就是:避免了完整复制(深拷贝)占用时间和空间,想象一下如果一个嵌套非常多层的庞大的对象,如果深拷贝一下,不仅耗时还非常占内存。

2. js语言特性对immutable 支持并不够友好

immutable 不可变,其实我们的数据变才是常态啊,immutable是不是有点反人类。我们回到immutable的起始点,它是解决什么问题的。它解决的是:干掉副作用,no-side-effect。那什么是副作用?什么是纯函数?

纯函数(pure funtion) : 输入啥,输出啥,只要输入的这个值是固定的,输出的值也是固定的。

敲黑板:前提是每次输入的值都是新的数据。假设一个对象a是函数参数,a在外面被改变了,那么它输出的值肯定就不是原来的那个值。a被改变了,还是作为函数输入参数,这就不纯了。

所以纯函数这个“纯”字你可以认为函数参数每次都是一个新的数据。等价于函数“蠢”,因为函数不管你是不是每次传入的是新值,就干执行,傻了吧唧的。传入的数据全靠(程序员)自觉。

所以副作用就不难理解了:那就是我们要高度自觉,每次都要生成新的数据。不是新的数据,就容易产生与我们本来预期不同结果,这就是副作用。

那么回到小标题,为啥说js语言特性对immutable支持不是很好,因为没有内置api 啊,没有语言级别的约束白保证输出是个immutable,我们要借助三方的库才能实现一个immutable。如果js 直接有一个deepClone 的内置接口多香。