Die Implementierung von
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(); });
ist unserer vorherigen Implementierung von reactive
tatsächlich sehr ähnlich. Der Unterschied besteht darin, dass der Trigger nicht ausgelöst wird, wenn set
verwendet wird, sondern eine Warnung . Da es natürlich nicht geändert wird, ist track
nicht erforderlich. 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<any> ) { return new Proxy(target, baseHandlers); } export function reactive(target) { return createReactiveObject(target, mutableHandler); } export function readonly(target) { return createReactiveObject(target, readonlyHandler); }
readonly
und reactive
tatsächlich sehr ähnlich sind, sodass wir sie umgestalten können, um die spätere Skalierbarkeit zu verbessern. 🎜🎜Was ich gesagt habe, ist ähnlich, es bezieht sich auf einige Traps (Capturer) in den Handlern (Prozessorobjekten) in new Proxy(target, handlers)
. Das heißt, get
, set
dieser Methoden. 🎜🎜Wir können diese Traps-Funktionen über Factory-Funktionen erstellen, um unseren Code zu vereinfachen und die Wartbarkeit zu verbessern. 🎜🎜Darüber hinaus gehen wir davon aus, dass Traps von Fabriken erzeugt werden können, das heißt, der Handler-Teil entspricht der Bestimmung, und der neue Proxy
-Teil sollte ebenfalls über die Fabrikfunktion erstellt werden. 🎜🎜Wir extrahieren zuerst eine öffentliche Datei baseHandler.ts
🎜rrreee🎜und dann unsere reactive.ts
🎜rrreeeDas obige ist der detaillierte Inhalt vonWas ist die Methode, um in vue3 schreibgeschützt und reaktionsfähig zu implementieren?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!