目录
[一、什么是 Proxy](#一、什么是 Proxy)
[二、常用的拦截操作(handler traps)](#二、常用的拦截操作(handler traps))
[1. get ------ 拦截对象属性的读取](#1. get —— 拦截对象属性的读取)
[2. set ------ 拦截对象属性的赋值](#2. set —— 拦截对象属性的赋值)
[3. has ------ 拦截 in 操作符](#3. has —— 拦截 in 操作符)
[4. deleteProperty ------ 拦截 delete 操作](#4. deleteProperty —— 拦截 delete 操作)
[5. apply ------ 拦截函数调用](#5. apply —— 拦截函数调用)
[6. construct ------ 拦截 new 操作](#6. construct —— 拦截 new 操作)
[三、Proxy 的应用场景](#三、Proxy 的应用场景)
[四、Proxy 与 Object.defineProperty 的区别](#四、Proxy 与 Object.defineProperty 的区别)
一、什么是 Proxy
Proxy
是 ES6 引入的一个强大功能,意思是"代理"。它可以用来拦截对象的操作,并在操作时进行自定义的逻辑处理。
你可以把 Proxy 理解成:
👉 在 对象 和 外部访问者 之间加了一层"代理层",所有对对象的操作都会先经过 Proxy,从而让我们有机会"改写"这些操作。
语法如下:
javascript
let proxy = new Proxy(target, handler);
-
target
:要代理的对象(可以是对象、数组、函数等) -
handler
:包含拦截方法的对象,不同的方法对应不同的拦截操作
二、常用的拦截操作(handler traps)
1. get
------ 拦截对象属性的读取
javascript
const user = {
name: "Tom",
age: 18
};
const proxy = new Proxy(user, {
get(target, prop) {
if (prop === "age") {
return target[prop] + " 岁";
}
return target[prop];
}
});
console.log(proxy.name); // Tom
console.log(proxy.age); // 18 岁
👉 在读取 age
时被拦截,返回了一个自定义的字符串。
2. set
------ 拦截对象属性的赋值
javascript
const user = {};
const proxy = new Proxy(user, {
set(target, prop, value) {
if (prop === "age") {
if (typeof value !== "number") {
throw new TypeError("年龄必须是数字!");
}
}
target[prop] = value;
return true; // 必须返回 true 表示赋值成功
}
});
proxy.age = 20;
console.log(proxy.age); // 20
proxy.age = "abc"; // 报错:年龄必须是数字!
👉 可以在设置属性时做数据校验,非常适合做表单验证。
3. has
------ 拦截 in
操作符
javascript
const user = { name: "Tom", password: "123456" };
const proxy = new Proxy(user, {
has(target, prop) {
if (prop === "password") {
return false; // 隐藏 password 属性
}
return prop in target;
}
});
console.log("name" in proxy); // true
console.log("password" in proxy); // false
👉 可以用来隐藏敏感信息。
4. deleteProperty
------ 拦截 delete
操作
javascript
const user = { name: "Tom" };
const proxy = new Proxy(user, {
deleteProperty(target, prop) {
if (prop === "name") {
console.log("name 属性不能被删除!");
return false;
}
return true;
}
});
delete proxy.name; // name 属性不能被删除!
console.log(proxy.name); // Tom
5. apply
------ 拦截函数调用
javascript
function sum(a, b) {
return a + b;
}
const proxy = new Proxy(sum, {
apply(target, thisArg, args) {
console.log("拦截函数调用,参数是:", args);
return target(...args) * 2; // 返回值改为原函数结果的两倍
}
});
console.log(proxy(1, 2)); // 6
6. construct
------ 拦截 new
操作
javascript
class Person {
constructor(name) {
this.name = name;
}
}
const ProxyPerson = new Proxy(Person, {
construct(target, args) {
console.log("正在创建实例,参数:", args);
return new target(...args);
}
});
const p = new ProxyPerson("Tom");
// 正在创建实例,参数: [ 'Tom' ]
三、Proxy 的应用场景
-
数据验证(如 set 中校验数据类型)
-
隐藏属性(如 has、get 中屏蔽敏感数据)
-
调试/日志记录(在 get/set 时记录日志)
-
自动填充默认值(属性不存在时返回默认值)
-
函数增强(apply 中扩展函数功能)
-
Vue3 响应式实现(Vue3 底层用 Proxy 实现数据劫持)
四、Proxy 与 Object.defineProperty 的区别
在 Vue2 中,响应式是通过 Object.defineProperty
实现的,而 Vue3 改用了 Proxy。
-
Object.defineProperty
只能监听对象的属性,不能监听对象本身 -
Proxy 能直接代理整个对象,不需要对每个属性单独处理
-
Proxy 能监听更多操作(如
in
、delete
、函数调用
等)
因此,Proxy 更加灵活、强大,也逐渐成为未来的主流。