本文深入解析 JavaScript 中 Proxy 对象的拦截原理,通过房屋中介案例类比代理模式。详细讲解 get 和 set 拦截器的具体用法,包括属性读取时的存在性校验以及属性赋值时的类型与范围限制,帮助开发者理解如何利用 Proxy 实现数据访问的控制与校验。
什么是代理模式
引入一个现实生活中的案例
作为普通用户,我们是否需要亲自参与房屋评估、办理繁琐的住房手续等全过程?显然并非如此。用户的核心诉求仅在于获取满意的居住结果,即提出需求并支付相应金额即可。
解决这一系列复杂流程的角色是“房屋中介”。该机构在房地产供求市场中,为交易标的提供评估、交易代理、咨询及后续服务,充当了供需双方之间的桥梁。
结合案例理解代理模式的定义
当某个对象因故不适合或无法被客户端直接引用时,可引入代理对象作为中介,由代理对象负责与目标对象交互。
代理模式的核心在于为客户端提供一层代理,使客户端无需关注底层具体实现过程,只需关注最终结果。代理对象负责处理中间复杂的业务逻辑。
什么是Proxy
Proxy 支持多种拦截操作,本文重点阐述 get(target, propKey, receiver) 和 set(target, propKey, value, receiver) 两种核心拦截器。
- get 方法:用于拦截对象属性的读取操作;
- set 方法:用于拦截对象属性的赋值操作。
get(target, propKey, receiver)
首先定义一个 Person 对象,该对象将被 Proxy 包裹,外部通过 Proxy 实例来访问 Person 对象的属性。
var person = {
name: "kongsam",
age: 21,
hobbies: [
"看动漫",
"骑行",
"玩游戏"
]
}
创建一个 Proxy 实例,用于拦截外部对 Person 对象的所有操作请求。
var proxy = new Proxy(person, {
get: function (target, property) {
// 打印target和property,查看里面到底是什么。
console.log("target = ", target);
console.log("property = ", property);
// 判断外界访问的对象属性是否存在于目标对象中。
if (property in target) {
return target[property];
} else {
// 如果外界访问的对象属性不存在与目标对象中,抛出异常。
throw new ReferenceError('Property "' + property + '" 不存在。');
}
},
});
当执行 proxy.name 操作时,由于 Person 已被 Proxy 代理,任何通过该 Proxy 实例访问 Person 中已存在属性的行为,都会触发 get 方法,从而实现对属性读取的拦截。
在 get: function (target, property) 中,target 和 property 两个参数分别接收目标对象和属性名,具体数据流向如图所示

通过代理对象访问 Person 中已存在的属性不会报错,但如果访问不存在的属性会发生什么?

究竟是什么机制导致访问不存在的属性时抛出异常?
这是因为外部对 Person 对象的访问必须经过 Proxy 设置的拦截层,该拦截层提供了过滤和改写访问请求的机制。
// 判断外界访问的对象属性是否存在于目标对象中。
if (property in target) {
return target[property];
} else {
// 如果外界访问的对象属性不存在与目标对象中,抛出异常。
throw new ReferenceError('Property "' + property + '" 不存在。');
}
代码中的 if 语句构成了拦截层的具体逻辑,即对访问请求进行过滤和改写。若缺少此判断,访问不存在的属性将直接返回 undefined。

set(target, propKey, value, receiver)
继续使用 Person 对象,此时新增需求:修改 age 属性时,要求值必须为整数且不超过 150。
在 Proxy 对象中新增 set 方法以处理赋值逻辑。
var proxy = new Proxy(person, {
set: function (target, property, value) {
// 打印target、property和value,查看里面到底是什么。
console.log("target = ", target);
console.log("property = ", property);
console.log("value = ", value);
if (property === "age") {
if (!Number.isInteger(value)) {
throw new TypeError("age的值不是整数!");
}
if (value > 150) {
throw new RangeError("age的值不能大于150!");
}
}
},
});
当执行 proxy.age = 100 时,set 方法的三个参数分别接收目标对象、属性名和赋值,具体数据如图所示。

set 方法用于拦截属性赋值操作,如果 age 的赋值不满足预设条件,将会发生什么?

显然,程序会抛出异常以阻止非法赋值。
总结
Proxy 本质上是一个拦截层。用户传入目标对象,外部对该对象的访问必须经过 Proxy 实例。通过 Proxy 可实现对访问行为的过滤和改写,例如在赋值时强制满足特定条件。
Proxy 对象还包含 has、deleteProperty、ownKeys、getOwnPropertyDescriptor 等其他拦截方法,用于处理不同的拦截场景。
以上就是 js Proxy 的原理详解的详细内容,更多关于 js Proxy 的资料请关注本站其它相关文章!