实现 shallowReadonly 功能
什么是shallowReadonly?
顾名思义 — 就是只把对象表层转换成readonly类型。当项目太过庞大时,有些数据没必要全部转换响应式对象,从而实现一定的程序优化。
shallowReadonly,可以想象成 readonly 的表亲,除了没有嵌套转化对象,其余功能都是一样的,同样不可以被修改。
shallowReadonly.spec.ts
import {
isReadonly, shallowReadonly } from "../src/reactive";
describe("shallowReadonly", () => {
// 只做表层的响应式,内部对象不是响应式,节约性能
it("should not make non-reactive properties reactive", () => {
const props = shallowReadonly({
p: {
bar: 1 } });
expect(isReadonly(props)).toBe(true);
expect(isReadonly(props.p)).toBe(false);
});
it("warning when set triggered", () => {
// mock console.warn 警告函数调用
console.warn = jest.fn();
const user = shallowReadonly({
age: 10,
});
user.age = 11;
expect(console.warn).toBeCalled();
});
});
接下来,实现他具体的逻辑。
reactive.ts
...
export function shallowReadonly(raw) {
return createActiveObj(raw, shallowReadonlyHandlers);
}
...
这里,抽离出shallowReadonlyHandlers,然后单独实现。达到代码复用性和统一性。
shallowReadonly同样可以参考 readonly 逻辑,在创建 ge t时,用 shallow 去打上标识,当 shallow 为 true 时,不用转换嵌套对象以及依赖收集。所以直接返回即可。
然后继承 readonly 的 handlers,再改写专属的 get 方法即可,最后导出 shallowReadonlyHandlers
baseHandlers.ts
...
const shallowReadonlyGet = createGetter(true, true);
function createGetter(isReadonly: Boolean = false, shallow: Boolean = false) {
return function get(target, key) {
if (key === ReactiveFlags.IS_REACTIVE) {
return !isReadonly;
} else if (key === ReactiveFlags.IS_READONLY) {
return isReadonly;
}
const res = Reflect.get(target, key);
// 判断是否是 shallow
if (shallow) return res;
// 判断内部属性是否是 Object,是的话继续转换成 Proxy
if (isObject(res)) {
return isReadonly ? readonly(res) : reactive(res);
}
if (!isReadonly) {
// 收集依赖
track(target, key);
}
return res;
};
}
export const shallowReadonlyHandlers = extend({
}, readonlyHandlers, {
get: shallowReadonlyGet,
});
以上,执行测试,通过
最后
附上git代码地址:mini-vue,共勉。