不可变数据类型
immutable,副作用,纯函数关键词解释:
- immutable: 不可变数据
- 副作用:调用函数,同时对主函数产生了附加的影响,比如修改全局变量,改变参数。
如何避免,创建不可变数据类型,在一次更新过程中不应该改变原有对象,需要返回一个新的对象 - 纯函数:无副作用的函数
js 中的对象一般是可变的,因为使用了引用赋值,虽然可以节约内存,但是会有一些隐患。一般做法使用浅拷贝和深拷贝来避免修改,但是这样会造成 CPU 和内存浪费。
为了解决这个问题,出现了 immutable.js 和 immer
immutable.js 库
immutable.js 实现原理:Persistent Data Structure
(持久化数据结构)。
- 使用旧数据创建新数据时,要保证旧数据同时可用且不变。同时为了避免 deepCopy 把所有节点否复制一遍带来的性能问题, immutable 使用了
Structural Sharing
(结构共享),即如果对象树中的一个节点改变,只修改这个节点和受它影响的父节点,其他节点共享。 -
immutable-js
使用了另一套数据结构 api,它会将原生数据类型都转化为 immutable-js 内部对象。
内部实现了一套 Persistent Data Structure,还有很多易用的数据类型像 Collection
、List
、Map
、Set
、Record
、Seq
。有非常全面的map
、filter
、groupBy
、reduce``find
函数式操作方法。同时 API 也尽量与 Object 或 Array 类似。
缺点:
- 需要学习新的 API
- 容易与原生对象混淆。
Immutable 中的 Map 和 List 虽对应原生 Object 和 Array,但操作非常不同,比如你要用map.get('key')
而不是map.key
,array.get(0)
而不是array[0]
。另外 Immutable 每次修改都会返回新对象,也很容易忘记赋值。
和 redux 的配合使用,redux 简化了 Flux 中多个 store 的概念,只有一个 store,数据操作通过 reducer 使用。reducer 就是要接受一个纯函数。
const reducer = function (state, action) {
// ...
return new_state;
};
immer
mobx 作者写的一个 immutable 库,核心实现利用 es6 的 proxy。
immer 使用原生数据结构的 api,而不像 immutable-js 转化为内置对象的 api。
学习成本低,就是把之前的操作放置到 produce 函数的第二参数函数中去执行。
原理:使用了一个 ES6 的新特性 Proxy 对象。深层嵌套对象的结构化共享的处理
proxy 具体可以看 Proxy
var proxy = new Proxy(target, handler);
- target 参数表示所要拦截的目标对象。如果没有 Proxy 的介入,操作原来要访问的就是这个对象
- handler 参数也是一个对象,用来定制拦截行为。对于每一个被代理的操作,需要提供一个对应的处理函数,该函数将拦截对应的操作
Proxy 无法 polyfill,所以 immer 在不支持 Proxy 的环境中,使用 Object.defineProperty 来进行一个兼容。
immer 维护一份 state 在内部,劫持所有操作,内部来判断是否有变化从而最终决定如何返回。