Proxy 与 Reflect 的常见使用场景
有以下三种:
数据绑定与观察者模式
函数参数的验证
简便的构造函数
1.数据绑定与观察者模式
实现数据绑定与观察者模式,也可以使用 ES5 新增的 Object.defineProperty()方法,Vue2 就是使用该技术实现的,而 Vue3 为什么换用 Pro 需要来实现呢?
所以现在先来对比一下这两种实现方法。
1.1 Object.defineProperty()方法实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<div id="container"></div>
<script>
//创建一个观察者 target为被观察的目标
function observer(target) {
const div = document.getElementById("container");
const ob = {}; //创建一个观察对象
const props = Object.keys(target);
for (const prop of props) {
//给ob新增属性
Object.defineProperty(ob, prop, {
get() {
return target[prop];
},
set(val) {
target[prop] = val;
render();
},
enumerable: true,
});
}
render();
//渲染函数,将ob的属性与属性值渲染到视图上
function render() {
let html = "";
for (const prop of Object.keys(ob)) {
html += `<p><span>${prop}:</span><span>${ob[prop]}</span></p>`;
}
div.innerHTML = html;
}
return ob;
}
const target = {
a: 1,
b: 2,
};
const obj = observer(target);
</script>
</body>
</html>
1.2 Proxy 与 Reflect 方法实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<div id="container"></div>
<script>
//创建一个观察者
function observer(target) {
const div = document.getElementById("container");
//为被观察的目标 创建一个代理对象
const proxy = new Proxy(target, {
set(target, prop, value) {
Reflect.set(target, prop, value);
render();
},
get(target, prop) {
return Reflect.get(target, prop);
},
});
render();
//渲染函数
function render() {
let html = "";
for (const prop of Object.keys(target)) {
html += `<p><span>${prop}:</span><span>${target[prop]}</span></p>`;
}
div.innerHTML = html;
}
return proxy;
}
const target = {
a: 1,
b: 2,
};
const obj = observer(target);
</script>
</body>
</html>
1.3 两种实现方法的对比
Proxy 与 Reflect 主要有以下优点:
直观角度上来看,Proxy 与 Reflect 方法的代码量更少,而且直接调用了对应的 API,可阅读性也更强,更容易看懂代码。
Proxy 与 Reflect 方法不用去新增一个 ob 对象,而是只需要创建一个代理对象,这样就不会占用内存,会减少内存消耗。
最后也是最重要的一点,Proxy 与 Reflect 方法可监听目标新增的属性以及目标删除的属性,而 Object.defineProperty()方法无法实现动态监听,所以在 Vue2 中需要使用 set 以及 set 以及 set 以及 delete 方法来进行响应式数据的增加与删除。
2.函数参数的验证
由于 Javascript 是一种动态类型语言,不能像 C 语言与 Java 一样限定数据的类型,平时在进行函数传参是偶尔会遇到一定的麻烦,所以可使用 Proxy 对象的 apply 捕获器实现函数参数的验证,对参数进行审查,不符合条件的参数,给予对应的提示。
如当需要给两数相加 sum()函数限定两个参数 a,b 都为 Number 类型。
//封装的 函数参数验证 方法
function validatorFunction(func, ...types) {
const proxy = new Proxy(func, {
//调用目标函数时触发该捕获器
apply(target, thisArgument, argumentsList) {
//thisArg:调用函数时的 this 参数。
//argumentsList:调用函数时的参数列表
//types为传入的参数数据类型数组 当前为["number", "number"]
types.forEach((t, i) => {
if (typeof argumentsList[i] !== t) {
throw new TypeError(
`第${i + 1}个参数${argumentsList[i]}不满足类型${t}`
);
}
});
return Reflect.apply(target, thisArgument, argumentsList);
},
});
return proxy;
}
//简单的两数相加函数
function sum(a, b) {
return a + b;
}
const sumProxy = validatorFunction(sum, "number", "number");
console.log(sumProxy(1, 2));
3.简便的构造函数
因为平时使用 Class 运算符构建一个类时,需要写大量的重复代码,使用可以使用 Proxy 对象的 construct 捕获器实现代码简化,并且还可以对属性传值进行一定的限制。
如当创建一个简单的 User 类,共有 name、sex、age 这三个属性。
//封装的 简便构造函数 方法
function ConstructorProxy(Class, ...propNames) {
return new Proxy(Class, {
//在 new 操作符中调用该捕获器
construct(target, argumentsList, newTarget) {
//target:目标构造函数
//argumentsList:传给目标构造函数的参数列表。
//newTarget:最初被调用的构造函数。
const obj = Reflect.construct(target, argumentsList);
//propNames 为创建代理对象时,传入的构造函数的属性列表 目前为["name", "sex", "age"]
propNames.forEach((name, i) => {
obj[name] = argumentsList[i];
});
return obj;
},
});
}
//创建User类
class User {}
const UserProxy = ConstructorProxy(User, "name", "sex", "age"); //传入属性名
const obj = new UserProxy("xx", "男", 18); //创建实例,并传入属性值
console.log(obj);
//创建Phone类
class Phone {} //User {name: 'xx', sex: '男', age: 18}
const ProductProxy = ConstructorProxy(Phone, "brand", "price", "inventory");
const phone1 = new ProductProxy("华为", 4000, 100);
console.log(phone1); //Phone {brand: '华为', price: 4000, inventory: 100}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南