如何在Vue3中实现只读(readonly)响应式属性?
readonly的实现it("happypath",()=>{console.warn=vi.fn();constoriginal={foo:1,};constobserved=readonly({foo:1,});expect(original).not.toBe(observed);expect(observed.foo).toBe(1);//set不起作用observed.foo=2;expect(observed.foo).toBe(1);//当被set的时候,发出一个警告expect(conso
readonly的实现
it("happy path", () => {
console.warn = vi.fn();
const original = {
foo: 1,
};
const observed = readonly({
foo: 1,
});
expect(original).not.toBe(observed);
expect(observed.foo).toBe(1);
// set不起作用
observed.foo = 2;
expect(observed.foo).toBe(1);
// 当被set的时候,发出一个警告
expect(console.warn).toBeCalled();
});其实与我们之前实现 reactive 十分的类似,区别只不过是set 的时候不要触发trigger,而是警告。当然既然是不会被改变的,track 也是不必要的。
export function readonly(raw) {
return new Proxy(raw, {
get(target, key) {
const res = Reflect.get(target, key);
return res;
},
set(target, key, newValue, receiver) {
console.warn(
`property: ${String(key)} can't be set, beacase ${target} is readonly.`
);
return true;
},
});
}
export function reactive(raw) {
return new Proxy(raw, {
get(target, key) {
const res = Reflect.get(target, key);
// 依赖收集
track(target, key);
return res;
},
set(target, key, value) {
const res = Reflect.set(target, key, value);
// 触发依赖
trigger(target, key);
return res;
},
});
}重构
可以看到,readonly 和 reactive 实现其实很类似,那我们可以重构一下,增强后续的拓展性。
至于我说的类似,指的是 new Proxy(target, handlers) 中的handlers(处理器对象)中的一些traps(捕获器)。即get, set 这些方法。
我们可以通过工厂函数来创建那些traps函数,来简化我们的代码,提高可维护性。
另外,我们假定traps可以有工厂可以生产了,即handlers这部分相当于被定下来了,new Proxy 这部分也理应可以通过工厂函数创造出来。
我们先抽出一个公共的文件 baseHandler.ts
// baseHanlder.ts
import { track, trigger } from "./effect";
// get的工厂函数
function createGetter(isReadonly = false) {
return function get(target, key) {
const res = Reflect.get(target, key);
if (!isReadonly) {
track(target, key);
}
return res;
};
}
function createSetter() {
return function set(target, key, newValue, receiver) {
const res = Reflect.set(target, key, newValue, receiver);
trigger(target, key, type, newValue);
return res;
};
}
export const mutableHandler = {
get: createGetter(),
set: createSetter(),
};
export const readonlyHandler = {
get: createGetter(),
set(target, key, newValue, receiver) {
console.warn(
`property: ${String(key)} can't be set, beacase ${target} is readonly.`
);
return true;
};然后是我们的reactive.ts
// reactive.ts
import {
mutableHandler,
readonlyHandler,
} from "./baseHandlers";
// proxy的工厂函数
function createReactiveObject(
target,
baseHandlers: ProxyHandler
) {
return new Proxy(target, baseHandlers);
}
export function reactive(target) {
return createReactiveObject(target, mutableHandler);
}
export function readonly(target) {
return createReactiveObject(target, readonlyHandler);
}
Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。
极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。
















