这是我参与「第五届青训营 」伴学笔记创作活动的第 17 天
前言
当我们想修改一个引用类型的数据的时候,为了不污染原数据,通常会使用深拷贝去拷贝一份数据来修改
// example
const info = {
name: 'xiaoming',
age: 30
}
const info2 = deepClone(info)
info2.age = 35
console.log(me)
但是,拷贝并非是一个完美的解法,拷贝意味着重复,而重复往往伴随着着冗余,当数据量过大时,容易降低页面性能,影响用户体验。
假设有这么一个数据,里面有1000个字段,而我只是想修改其中的一两个字段,所以我们会想到先拷贝整个数据,但是每次变更那些相同数值的字段的时候都会形成冗余,so,当数据规模大、数据拷贝行为频繁时,拷贝将会给我们的应用性能带来巨大的挑战。
immutable.js登场
- Immutable data cannot be changed once created, leading to much simpler application development, no defensive copying, and enabling advanced memoization and change detection techniques with simple logic. Persistent data presents a mutative API which does not update the data in-place, but instead always yields new updated data.
作为一个vue的开发者,我对此是陌生的,当我了解到immutable.js的强大后,我发现我已经深深的喜欢上了他。下面用一个demo来感受一下
let A = Immutable.fromJS({
b: 1,
c: {
c1: 123,
},
})
let B = A.set('b', 2)
// 对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象
console.log(A.get('b'), B.get('b')) // 1, 2 对象 A 的 b 值并没有变成2。
console.log(A === B) // false
我们可以发现,他省掉了我们手动拷贝的麻烦,而且他还在底层做了持久化数据结构,解决了我们暴力循环拷贝带来的性能问题
精髓
immutable.js的精髓在于数据共享,他仅仅会创建变化的那部分,那对于不变的部分他会生成一套指针指向原对象,从而达到复用的效果。例如:
上面的例子中就是 Immutable.js 仅仅会创建变化的那部分,也就是创建了一个b字段给B,并且为B对象生成了一套指回A的对象,那它是如何做到这样的呢?
如何实现数据共享
引用一句话:为了达到这种“数据共享”的效果,持久化数据结构在底层依赖了一种经典的基础数据结构,那就是 Trie(字典树)。这里偷了个懒,直接引用一张图片。
在字典树的加持下,一个对象的存储可以是这样子
然后创建B对象的时候,我们就可以针对仅仅发生变化的字段创建一条新的数据,并把剩余的指针指向原数据
总结
- immutable是一个完全独立的库,无论基于什么框架都可以用它。意义在于它弥补了
Javascript没有不可变数据结构的问题 - 不过它容易与原生对象混淆
- 这几年又出了一个新的 immutable 库,叫做 immer(MobX 作者写的)。它就覆盖了 immutable 的功能的同时,还做到了api更加简洁
- 且Immutable在React中的使用频率较高,不知道vue有没有这么一个东西呢?