immer介绍
immer 是国外大佬Michel Weststrate写的一个不可变数据结构库,其核心是利用 ES6 的 Proxy 来代理数据,我们在这个代理数据上所做的修改都会被记录下来,最后再由 immer 根据这些记录去生成一个不会影响到原始数据的副本。
简单来说,immer 就是一种拷贝技术,区别于我们常用的浅拷贝和深拷贝,它是一种对引用数据类型进行局部的深度浅拷贝技术,先看段代码:
import { createDraft, finishDraft } from "immer"
const base = {
a:{
b: 0,
c:[]
},
d: []
}
const draft = createDraft(base) // 创建代理对象
draft.a.b = 666
const copy = finishDraft(draft) // 进行拷贝
console.log(base === copy) // false
console.log(base .a === copy.a) // false
console.log(base.a.b === copy.a.b) // false
console.log(base.a.c === copy.a.c) // true
console.log(base.d === copy.d) // true
如上,从打印结果来看,只有重新被赋值的 draft.a.b 所经过的结点被浅拷贝了,而 draft.a.c 和 draft.d 依旧维持原来的引用。由此可以看出,immer 对数据的拷贝是一个局部的深度浅拷贝过程,相较于深拷贝把所有结点都拷贝一次来说,immer 拷贝的成本要低的多。
背景
由于目前的 immer 并不支持动态注入拦截操作,笔者又有这方面的需求,没办法只能自己手撸一个了,也好在 immer 只是一个小型包,只要了解了其原理,写起来还是相对比较简单的,这里也分享给其他有需要的人。
npm下载:
npm i handleable-immutable
handleable-immutable介绍
handleable-immutable 的拷贝原理和 immer 一样,同时还支持动态注入拦截操作,用法如下:
import { createImmutable, getImmutableCopy, setHandler } from 'handleable-immutable'
- createImmutable( )
创建不可变代理对象,非引用类型数据会直接返回原数据,如下所示:
const obj = {
age: 26,
friends: [Tony, July]
}
const draft = createImmutable(obj, {
get(t, p, r){
console.log('trigger getter')
},
set(t, p, v, r){
console.log('trigger setter')
}
})
- getImmutableCopy( )
解包不可变代理对象,获取拷贝数据,如下所示:
const obj = {
a: [0, 1]
}
const draft = createImmutable(obj)
draft.a.push(3)
const copy = getImmutableCopy(draft)
console.log(copy) // Expected output: { a: [1, 2, 3] }
- setHandler( )
动态注入getter、setter,会替换初始化时的getter、setter,用法如下:
const obj = {
a: [0, 1]
}
const draft = createImmutable(obj, {
set(t, p, v, r){
console.log('init setter')
}
})
// 动态注入拦截操作,覆盖原来的setter
setHandler(draft, {
set(t, p, v, r){
console.log('reset setter')
}
})
obj.a = 1 // Expected output: reset setter
结语
handleable-immutable和immer一样采用了局部深度浅拷贝的方法,降低了拷贝成本,同时还支持拦截操作,有需要的小伙伴可以试试看。
创作不易,如果觉得对你有帮助的话,麻烦帮我点点赞,点点关注,github 上点点 star(地址:handleable-immutable),这对我真的很重要,感激不尽!!!