引用数据类型
1 | let currentState = { |
解决方法
- 深度拷贝,但是如果数据量巨大,那么深度拷贝所消耗的成本较高,会影响性能;
- ImmutableJS,使用起来不够方便
- immer
immer简单使用方法
- 当我们调用 immer 的 API produce时,immer 将内部暂时存储着我们的目标对象
- immer 暴露一个 draft (草稿)给我们
- 我们在 draft 上作修改
- immer 接收修改后的draft,immer 基于传入的 目标对象 照着draft 的修改 返回一个新的 对象produce
1
produce(currentState, recipe: (draftState) => void | draftState, ?PatchListener): nextState
currentState
被操作对象的最初状态
draftState
根据 currentState 生成的草稿状态,它是 currentState 的代理,对 draftState 所做的任何修改都将被记录并用于生成 nextState 。在此过程中,currentState 将不受影响
nextState
根据 draftState 生成的最终状态
produce 生产
用来生成 nextState 或 producer 的函数。
roducer 生产者
通过 produce 生成,用来生产 nextState ,每次执行相同的操作。
recipe 生产机器
用来操作 draftState 的函数。
自动冻结功能
Immer 还在内部做了一件很巧妙的事情,那就是通过 produce 生成的 nextState 是被冻结(freeze)的,(Immer 内部使用Object.freeze
方法,只冻结 nextState 跟 currentState 相比修改的部分),这样,当直接修改 nextState 时,将会报错。这使得 nextState 成为了真正的不可变数据。
COW Copy-on-write
写时再进行复制,当我们复制资源操作只是利用一个引用将副本和原版共享资源,当我们去修改这个资源的时候再去进行创建副本。
有的时候复制这件事没多大必要,完全可以复用之前的,这时候可以只是引用之前的那份,在写内容的时候才去复制对应的一部分内容。这样如果内容用于读的话,就免去了复制,而如果需要写,才会真正复制部分内容来做修改。这种技术在操作系统的内存管理和文件系统中很常见。
COW策略应用
- 虚拟内存管理:进程共享虚拟内存、fork()系统调用等
- 存储:逻辑卷管理、文件系统、数据库快照
- 编程语言:PHP、Qt 中的许多数据类型
- 数据结构:实现不可变的数据结构,如状态树
Proxy
大家肯定对proxy都很熟悉了,利用proxy去监听数据变化,进行操作拦截。促使数据变为不可变的。
1 | var proxy = new Proxy(target, handler) |
target
表示所要拦截的目标对象(任何类型的对象,包括原生数组,函数,甚至另一个代理))handler
通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p
的行为
- set(target,propKey,value,receiver):拦截对象属性的设置 (主要使用)
模拟一个简单的produce
1 | function produce(data, producer) { |