Mastering JavaScript Proxy and Reflect: Deep Dive into Vue 3 Reactivity
This article explains how Vue 3 replaces Vue 2’s Object.defineProperty reactivity with JavaScript’s Proxy, covering Proxy fundamentals, handler traps, the relationship with Reflect, internal methods and slots, and the distinction between ordinary and exotic objects, providing code examples and visual diagrams.
Preface
Vue 2’s reactivity system uses Object.defineProperty for data hijacking, which has several drawbacks: it must traverse each property of ordinary objects, cannot detect array changes, cannot monitor Map/Set mutations, and cannot observe addition or deletion of object properties.
Vue 3 adopts Proxy for reactivity, packaged in the @vue/reactivity module. Understanding Proxy is essential for mastering Vue 3’s reactivity.
Proxy Overview
Proxy creates a proxy for an object, allowing interception and customization of fundamental operations such as property lookup, assignment, enumeration, and function invocation.
Basic syntax: const p = new Proxy(target, handler); target is the object to be proxied; it can be any object, including arrays, functions, or another Proxy. Primitive values cannot be used as the target.
handler is an object whose properties are functions (traps) that define custom behavior for operations on the proxy.
Common traps include get, set, and apply. Example:
const obj = { foo: 'bar', fn() { console.log('fn called'); } };
const handler = {
get(target, key) {
console.log(`property ${key} was read`);
return target[key];
},
set(target, key, value) {
console.log(`property ${key} was set to ${value}`);
target[key] = value;
},
apply(target, thisArg, args) {
console.log('function call intercepted');
return target.apply(thisArg, args);
}
};
const p = new Proxy(obj, handler);
p.foo; // logs: property foo was read
p.foo = 'bar1'; // logs: property foo was set to bar1
p.fn(); // logs: property fn was read, then fn calledOnly basic operations are intercepted; compound operations like obj.fn() involve a property read followed by a function call, so only the read is trapped.
Reflect and Proxy
Reflect is a built‑in object that provides methods corresponding to the proxy traps.
For example, Reflect.get(obj, 'foo') performs the default property access.
const obj = { foo: 'foo' };
obj.foo; // same as
Reflect.get(obj, 'foo');Using Reflect.get inside a trap preserves the correct this binding:
const handler = {
get(target, key, receiver) {
console.log(`property ${key} was read`);
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
console.log(`property ${key} was set to ${value}`);
return Reflect.set(target, key, value, receiver);
}
};
const obj = { foo: 'foo', get bar() { return this.foo; } };
const p = new Proxy(obj, handler);
p.bar; // triggers both bar and foo reads when bar’s getter accesses this.fooHow Proxy Works Internally
Internal Methods and Slots
ECMAScript specifies object behavior via internal methods and internal slots, identified by double brackets [[...]]. When a property is accessed, the engine invokes the object's [[Get]] internal method.
Objects implement a set of fundamental internal methods; functions also implement [[Call]] and optionally [[Construct]].
Ordinary vs. Exotic Objects
Ordinary objects conform to the standard internal method definitions (e.g., the ten methods in §10.1.x). Exotic objects deviate from these definitions; Proxy is an exotic object because its internal methods are defined in §10.5.x.
Further Proxy Details
When a proxy’s get trap is absent, the operation falls back to the target’s [[Get]]. If the trap exists, it handles the operation on the proxy itself, illustrating the proxy’s transparent nature.
const obj = { foo: 'foo' };
const p = new Proxy(obj, {});
p.foo; // outputs: fooConclusion
The article introduced Proxy and its combination with Reflect, explained internal methods and slots from the ECMAScript specification, distinguished ordinary and exotic objects, and clarified how Proxy achieves object interception.
References
Proxy - JavaScript | MDN (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)
Reflect - JavaScript | MDN (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect)
ECMAScript® 2023 Language Specification (https://tc39.es/ecma262/)
Vue.js Design and Implementation (https://www.ituring.com.cn/book/2953)
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
WeDoctor Frontend Technology
Official WeDoctor Group frontend public account, sharing original tech articles, events, job postings, and occasional daily updates from our tech team.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
