一、单元测试
reactive
// src/reactivity/tests/reactive.spec.ts
it('nested reactive', () => {
const original = {
nested: { foo: 1 },
array: [{ bar: 2 }]
};
const observed = reactive(original);
expect(isReactive(observed.nested)).toBe(true);
expect(isReactive(observed.array)).toBe(true);
expect(isReactive(observed.array[0])).toBe(true);
});
readonly
it('nested readonly', () => {
const original = { foo: 1, bar: { baz: 2 } };
const wrapped = readonly(original);
expect(isReadonly(wrapped)).toBe(true);
expect(isReadonly(wrapped.bar)).toBe(true);
});
二、代码实现
为什么嵌套的深层对象没有转换成reactive
、readonly
呢?
因为Proxy
劫持的是对象本身,并不能劫持子对象的变化。
其实通过单测可以看出,我们只需要将reactive
嵌套的里层对象也转换成reactive
,将readonly
嵌套的里层对象也转换成readonly
。
那只需要在get
中,返回res
的时候,将res
转换成相应的代理就可以了。
function createGetter(isReadonly = false) {
return function get(target, key) {
const res = Reflect.get(target, key);
if (key === ReactiveFlags.IS_REACTIVE) {
return !isReadonly;
} else if (key === ReactiveFlags.IS_READONLY) {
return isReadonly;
}
if (isObject(res)) {
return isReadonly ? readonly(res) : reactive(res);
}
if (!isReadonly) {
track(target, key);
}
return res;
};
}
跑一下完整的单测结果看下:
ps: 其实这里需要注意的一点就是,在get
中处理嵌套转换,我们只有在用到这个子对象的时候,才会将这个子对象 转换成响应时代理,避免了不必要的性能浪费。对比vue2
的递归遍历defineProperty
来说,也是一个优化的地方。
以上就是reactive readonly嵌套对象转换功能实现详解的详细内容,更多关于reactive readonly嵌套对象转换的资料请关注编程网其它相关文章!