货源网站 源码,火车头采集器wordpress发布模块,深圳建筑,三种WordPress引流方法之前写了一篇介绍 Object.defineProperty的#xff0c;提到proxy#xff0c;二者有一些共性#xff0c;也都是前端框架Vue的核心机制#xff0c;所以再写一篇介绍一下proxy的基础原理和使用。
在 JavaScript 中#xff0c;Proxy 是 ES6 引入的一个元编程特性#xff0c;用…之前写了一篇介绍 Object.defineProperty的提到proxy二者有一些共性也都是前端框架Vue的核心机制所以再写一篇介绍一下proxy的基础原理和使用。
在 JavaScript 中Proxy 是 ES6 引入的一个元编程特性用于创建对象的代理从而可以拦截并自定义对该对象的基本操作如属性访问、赋值、枚举、函数调用等。与 Object.defineProperty() 相比Proxy 提供了更强大、更全面的元编程能力。
核心作用
拦截对象操作
通过定义拦截器trap可以捕获并自定义对象的各种操作如属性读取、赋值、函数调用等。实现元编程
允许修改语言的底层行为例如自定义属性访问权限、实现数据验证、模拟私有属性等。创建响应式系统
比 Object.defineProperty() 更适合实现响应式数据绑定如 Vue.js 3.x因为它能拦截更广泛的操作且支持深层监听。
基本语法
const proxy new Proxy(target, handler);target需要被代理的对象。handler一个对象包含拦截各种操作的陷阱函数trap。
常用拦截器Traps拦截器触发时机get(target, prop, receiver)读取属性时触发set(target, prop, value, receiver)设置属性值时触发has(target, prop)判断属性是否存在in 操作符deleteProperty(target, prop)删除属性时触发ownKeys(target)获取对象所有属性键如 Object.keys()apply(target, thisArg, args)代理函数调用时触发construct(target, args, newTarget)代理构造函数调用时触发new 操作符用法示例
1. 基本拦截属性读取和赋值
const person { name: John, age: 30 };const proxy new Proxy(person, {// 拦截属性读取get(target, prop) {console.log(读取属性 ${prop});return target[prop];},// 拦截属性赋值set(target, prop, value) {console.log(设置属性 ${prop} 为 ${value});if (prop age typeof value ! number) {throw new Error(年龄必须是数字);}target[prop] value;return true; // 表示赋值成功}
});console.log(proxy.name); // 读取属性 name → John
proxy.age 31; // 设置属性 age 为 31
proxy.age thirty; // Error: 年龄必须是数字2. 实现数据验证
const validator {set(target, prop, value) {if (prop age value 0) {throw new Error(年龄不能为负数);}target[prop] value;return true;}
};const person new Proxy({ age: 30 }, validator);
person.age -5; // Error: 年龄不能为负数3. 实现私有属性
const privateData new WeakMap();const createPerson (name, age) {privateData.set({ name, age }, { salary: 5000 });return new Proxy({ name, age }, {get(target, prop) {if (privateData.has(target) prop salary) {return privateData.get(target)[prop];}return target[prop];}});
};const person createPerson(John, 30);
console.log(person.name); // John
console.log(person.salary); // undefined外部无法访问4. 函数调用拦截
const sum (a, b) a b;const proxy new Proxy(sum, {apply(target, thisArg, args) {console.log(调用函数参数${args});return target(...args) * 2; // 结果翻倍}
});console.log(proxy(2, 3)); // 调用函数参数2,3 → 10与 Object.defineProperty() 的对比特性Object.defineProperty()Proxy监听范围只能监听对象的已有属性需逐个定义可以监听整个对象包括新增属性深层监听需要递归处理嵌套对象可以通过递归代理实现深层监听数组支持对数组的监听有限需特殊处理全面支持数组操作如 push、pop元编程能力仅能控制单个属性的行为可以拦截多种操作如 in、delete、函数调用等性能对于大量属性的对象性能略高对于频繁操作的场景性能略低兼容性ES5支持 IE9ES6不支持 IE应用场景响应式系统
Vue.js 3.x 使用 Proxy 替代 Object.defineProperty() 实现响应式数据
const reactive (target) {return new Proxy(target, {get(target, prop) {// 依赖收集return target[prop];},set(target, prop, value) {target[prop] value;// 触发更新updateDOM();return true;}});
};数据验证与转换
在属性赋值时自动验证或转换数据
const withValidation (target, validators) {return new Proxy(target, {set(target, prop, value) {if (validators[prop] !validators[prop](value)) {throw new Error(Invalid value for ${prop});}target[prop] value;return true;}});
};const person withValidation({ name: , age: 0 },{ age: (v) typeof v number v 0 }
);日志记录与性能监控
拦截对象操作并记录日志
const withLogging (target) {return new Proxy(target, {get(target, prop) {console.log(Getting ${prop});return target[prop];},set(target, prop, value) {console.log(Setting ${prop} to ${value});target[prop] value;return true;}});
};注意事项
兼容性Proxy 是 ES6 特性不支持 IE。性能开销Proxy 的拦截操作比直接访问对象属性有更高的性能开销不适合高性能场景。this 指向在 Proxy 的陷阱函数中this 指向 handler 对象而非 target 对象。反射 API通常与 Reflect 对象配合使用以保持原生行为const proxy new Proxy(target, {get(target, prop, receiver) {return Reflect.get(target, prop, receiver);}
});总结
Object.defineProperty()适合简单场景如单个对象的属性监听兼容性好但功能有限。Proxy适合复杂场景如框架开发、全面的数据拦截功能强大但有兼容性和性能限制。
选择哪种方式取决于具体需求若需要全面控制对象操作且不考虑 IE 兼容性Proxy 是更好的选择若需要兼容旧浏览器或仅需简单属性监听可使用 Object.defineProperty()。