我写了一个支持拦截操作的immer

519 阅读2分钟

immer介绍

immer 是国外大佬Michel Weststrate写的一个不可变数据结构库,其核心是利用 ES6 的 Proxy 来代理数据,我们在这个代理数据上所做的修改都会被记录下来,最后再由 immer 根据这些记录去生成一个不会影响到原始数据的副本。

简单来说,immer 就是一种拷贝技术,区别于我们常用的浅拷贝和深拷贝,它是一种对引用数据类型进行局部的深度浅拷贝技术,先看段代码:

import { createDraft, finishDraft } from "immer"

const base = {
    a:{
        b: 0c:[]
    },
    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-immutableimmer一样采用了局部深度浅拷贝的方法,降低了拷贝成本,同时还支持拦截操作,有需要的小伙伴可以试试看。

创作不易,如果觉得对你有帮助的话,麻烦帮我点点赞,点点关注,github 上点点 star(地址:handleable-immutable),这对我真的很重要,感激不尽!!!