这里只是简单描述,具体请看另一篇文章:Object.defineProperty。
Object.defineProperty 是 JavaScript 中用于定义或修改对象属性的功能强大的方法。它可以精确地控制属性的行为,如是否可枚举、可配置、可写等。
Object.defineProperty(obj, prop, descriptor) Object.defineProperty 方法接受三个参数:
let obj = {}; Object.defineProperty(obj, 'message', { value: 'Hello, world!', writable: false }); console.log(obj.message); // 输出 "Hello, world!" obj.message = 'Hi!'; // 无效,因为属性是只读的 console.log(obj.message); // 仍然输出 "Hello, world!" let obj = {}; Object.defineProperty(obj, 'message', { value: 'Hello, world!', enumerable: false }); console.log(obj.message); // 输出 "Hello, world!" console.log(Object.keys(obj)); // 输出 [], 因为属性不可枚举 let obj = {}; let value = 'Hello, world!'; Object.defineProperty(obj, 'message', { get() { return value; }, set(newValue) { value = newValue; }, enumerable: true, configurable: true }); console.log(obj.message); // 输出 "Hello, world!" obj.message = 'Hi!'; console.log(obj.message); // 输出 "Hi!" let obj = {}; Object.defineProperty(obj, 'message', { value: 'Hello, world!', configurable: false }); console.log(obj.message); // 输出 "Hello, world!" Object.defineProperty(obj, 'message', { value: 'Hi!' }); // 抛出错误,因为属性不可配置 Proxy 是 ES6 引入的一项功能,用于定义自定义行为来拦截并改变对某个对象的基本操作(例如属性读取、赋值、枚举、函数调用等)。
let proxy = new Proxy(target, handler); Proxy 构造函数接受两个参数:
traps)。这些捕捉器定义了在执行各种操作时,代理对象如何处理这些操作。let target = { message: "Hello, world!" }; let handler = { get(target, prop) { return prop in target ? target[prop] : `Property ${prop} does not exist.`; }, set(target, prop, value) { console.log(`Setting ${prop} to ${value}`); target[prop] = value; return true; } }; let proxy = new Proxy(target, handler); console.log(proxy.message); // 输出 "Hello, world!" console.log(proxy.nonExistent); // 输出 "Property nonExistent does not exist." proxy.message = "Hi!"; // 输出 "Setting message to Hi!" let target = function() { return "I am the target"; }; let handler = { apply(target, thisArg, argumentsList) { return "I am the proxy"; } }; let proxy = new Proxy(target, handler); console.log(proxy()); // 输出 "I am the proxy" let target = { message: "Hello, world!" }; let handler = { deleteProperty(target, prop) { if (prop in target) { delete target[prop]; console.log(`Property ${prop} deleted`); return true; } else { console.log(`Property ${prop} does not exist`); return false; } } }; let proxy = new Proxy(target, handler); delete proxy.message; // 输出 "Property message deleted" delete proxy.nonExistent; // 输出 "Property nonExistent does not exist" defineProperty 只能代理属性,Proxy 代理的是对象。defineProperty 如果想代理对象的所有属性,需要遍历并为每个属性添加 setter 和 getter。Proxy 只需要配置一个可以获取属性名参数的函数即可。
defineProperty 的代理行为会破坏原对象,它会将原本的 value 变成了 setter 和 getter。Proxy 则不会破坏原对象,只是在原对象上覆盖了一层。当新增属性时,希望属性被代理,defineProperty 需要显式调用该 API,而 Proxy 则可以直接用 obj.key = val的形式
| Object.defineProperty | Proxy | |
|---|---|---|
| 拦截范围 | 只能拦截对象的单个属性操作,即只能定义特定属性的getter和setter | 可以拦截对对象的所有操作,包括属性访问、赋值、删除、函数调用等,可以使用get、set、deleteProperty等捕捉器来拦截这些操作 |
| 动态属性 | 不可以处理动态属性 | 可以处理对象的动态添加和删除属性 |
| 是否破坏原对象 | 是 | 否 |
| 性能 | 性能逊于Proxy | 对于处理嵌套对象和大量属性的情况,性能好 |
| 兼容性 | 兼容性更好 | 由于ES6中才引入Proxy,所以兼容性略差 |
vue2响应式数据原理是Object.defineProperty。
Vue3响应式数据原理是Proxy。