认识
一、认识
Immer
实现的原理是: 基于 Proxy
来代理对象的各种操作,然后在数据进行操作时,Proxy
会去拷贝被修改对象,然后再进行数据操作,返回拷贝后并被修改的数据。 当数据被修改时,会返回一个对象,但是新的对象会尽可能的利用之前的数据结构而不会对内存造成浪费, 也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变,同时为了避免 deepCopy
把所有节点都复制一遍带来的性能损耗,Immer
使用了(结构共享)。如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享。
二、工作
-
使用
Proxy
来实现对对象属性的 增删改查 的监听 -
使用
handler.get
来拦截对象的读取属性操作,查到的属性值如果是一个对象,那么需要对该象进行代理,也就是对子对象也要使用Proxy
来管理,因此需要记录每一个被Proxy
的对象,这里将会新增proxies
内部状态来存储原对象和代理对象的关系。 -
使用
handler.set
来监听 增 和 改,因为被代理的对象每一次修改对象的属性值,都会被proxy
监听到,监听到修改后需要对对该对象进行拷贝 ,然后对拷贝的对象进行修改,而不直接修改原对象,永远不要直接修改原对象,因此需要记录每一个被拷贝的对象,这里将会新增copies
内部状态来存储原对象和拷贝对象的关系。 -
使用
handler.has
来监听in
操作符的查找方式。 -
使用
handler.ownKeys
来拦截Object.getOwnPropertyNames()
和Object.getOwnPropertySymbols()
属性获取,也可以拦截Object.keys()
和Reflect.ownKeys()
。 -
使用
handler.deleteProperty
来拦截删除操作,有拷贝的删除拷贝的属性,不能删除原对象。
2.2 handler get
使用 handler.get
来拦截对象的读取属性操作,查到的属性值如果是一个对象,那么需要对该象进行代理,也就是对子对象也要使用 Proxy
来管理,因此需要记录每一个被 Proxy
的对象,这里将会新增 proxies
内部状态来存储原对象和代理对象的关系。需要注意的是: 同一个属性可能被多次获取,并且被修改过,因此要优先判断是否被拷贝过,有拷贝直接从拷贝对象中去拿取属性,然后对拷贝的对象的属性进行设置代理(对象才会被代理,其他基本数据类型会直接返回)
2.3 handler set
使用 handler.set
来监听 增 和 改,因为被代理的对象每一次修改对象的属性值,都会被 proxy
监听到,监听到修改后需要对对该对象进行拷贝 ,然后对拷贝的对象进行修改,而不直接修改原对象,永远不要直接修改原对象,因此需要记录每一个被拷贝的对象,这里将会新增 copies
内部状态来存储原对象和拷贝对象的关系。需要注意如果值没有变化,则不需要进行拷贝。
2.4 handler has
使用 handler.has
来监听 in
操作符的查找方式。
2.5 handler delete
使用 handler.deleteProperty
来拦截删除操作,有拷贝的删除拷贝的属性,不能删除原对象。
2.6 handler ownKeys
使用 handler.ownKeys
来拦截 Object.getOwnPropertyNames()
和 Object.getOwnPropertySymbols()
属性获取,也可以拦截 Object.keys()
和 Reflect.ownKeys()
。
2.7 finalize
finalize
处理数据, 返回修改后的数据。基本思路: 如果数据没有改变, 直接原始数据。通过获取原始数据副本, 递归处理数据。
2.8 hasChanges
hasChanges
判断数据是否被改变。基本思路: 检测传入对象是否被代理, 如果没有被代理, 一定没有修改过(被代理的对象不一定被修改,被修改的一定被代理和拷贝)。随后检测传入对象是否被拷贝, 如果拷贝了, 那一定被改变了(被拷贝的对象,一定被修改,但子对象不一定被修改,因此后面进行了递归检查)。最后, 递归检查子数据。
2.9 createProxy
createProxy
用于创建代理, 被代理过的对象避免重复被代理,只有普通对象和数组才需要被代理。同一个属性可能被多次获取,并且被修改过,因此要优先判断是否被拷贝过,有拷贝直接从拷贝对象中去拿取属性,然后对拷贝的对象的属性进行设置代理(对象才会被代理,其他基本数据类型会直接返回)
2.10 getCurrentSource
被代理的对象不一定被修改,被修改的一定被代理和拷贝。数据如果被修改了很多次,那么我们获取正确数据的方法就是先查找数据是否被拷贝,被拷贝说明一定被修改了,没有被拷贝,说明没有被修改,因此实现一个 getCurrentSource
方法来查找对象,需要获取最新对象直接使用这个方法来查找
2.11 getOrCreateCopy
getOrCreateCopy
获取 copy
元对象,没有则进行创建。