Immutable -- 数据不可变性的实现

123 阅读3分钟

在项目里我们最好还是遵循数据不可变性,即更新状态时,不在 old 状态上修改,而是在 old 状态的基础上拷贝一份新的,在新状态上进行修改,并返回新状态!!!

而且在使用 Redux 管理状态时,我们在 reducer 函数中进行状态更新时,是不允许我们直接在 old 状态上修改的,而是需要我们返回拷贝+更新过后的新状态!!!

<1> 使用扩展运算符... 进行拷贝

并不能实现完全的深拷贝,只是比浅拷贝多复制了一层

缺点:

  • 即如果要拷贝的对象中有属性的值是对象的话,那么对该属性的拷贝还是浅拷贝,即还是拷贝的是对该属性值的对象的引用!!

1921.png

<2> 使用 json--parse json--stringify

确实能实现完全的深度拷贝

缺点:

  • 但是不能有 undefined ,即如果遇见值为 undefined ,就会自动把该值 pass 掉,不会对该值进行复制!!!

1922.png

<3> 手动进行 deepcopy

手动进行递归复制,一层一层的复制!!

缺点:

  • 性能不好,且占用内存!!

<4> Immutable

一个第三方库:

实现原理是 Persistent Data Structure(持久化数据结构),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变,同时为了避免 deepCopy 把所有的节点都复制一遍带来的性能损耗,Immutable库使用了 Structural Sharing(结构共享),及如果对象树种一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享!!!

如下图所示:

1923.png

1924.png

(1) 引入 Immutable
  • npm i immutable
  • import {Map} from 'immutable '
(2) Immutable 常用类型

1 . Map

Map 类型适用于原始数据为对象的转换

使用方法为,用Map() 方法包括要转换的原始数据即可。需要注意的是:

  • 如果要转换的对象里面也存有对象值的话,就也需要把存的对象值也用Map() 包括!!!

1926.png

  • 因为Immutable库使用了 Structural Sharing(结构共享),所以如果对象中存储的对象内容不改变的话,那么新旧状态会共同引用同一个存的对象值,可以利用该点,来避免不必要的渲染!!!提供性能!!!

1927.png

  • 修改的话,使用set() 方法,可以连续调用!!

1928.png

  • 获得状态的话,使用get() 方法

1929.png

  • Immutable 类型的数据转换为普通 JS 对象,用**immutable.toJS()**方法!!!

2 . List

Map 类型适用于原始数据为数组的转换

使用方法,跟封装的数据方法一样!!

1930.png

3 . 不依赖类型,只需要依赖两个方法

上述的两个类型,Map 和 List 都是在我们已经知道原始数据类型是对象 or 数组时才使用的,但如果我们不知道,有没有一种通用的方法呢?

fromJS(o)toJS():

1931.png

  • 使用该方法后,如果被转换的对象中存有值为对象or数组的属性,也会自动将它们转换为对应的 Map or List 类型

  • 修改状态,一级修改的话,set("","") or setIn(),方法

    - 两级修改,即修改对象中的对象时,用**setIn([] , "")** ,第一个参数采用数组模式,表明修改 n 级中的那个属性
    - 两极修改,如果是修改对象中的数组,就用下标代表要修改哪个!!
    

1932.png

1933.png

  • 增加or删除状态,用 updateIn([] , callback)

     - 在第一个参数中,选中要修改的属性
     - 第二个参数,回调函数中返回修改后的状态
    

1934.png

(2) 与 Redux 相结合

1935.png