与掘金文章同步:https://juejin.cn/post/6964398933229436935
什么是代理模式
引入一个现实生活中的案例
我们作为用户需要去如何评估一个房子7 z = k 4 # I z Z的好坏、如何@ J b W c办理住房手续等一些列繁琐的事物吗?显然,用户肯定不愿意这样做。用户最关心的是结果,用户对房A n K 8 \ q t U子提出需求+ ( 8 R以及提供对等价值的金钱就可以获得满意的房子,这就是结果。
那么谁为用户去解决一系列繁琐的买房过程呢?当然就是“房屋中介”了!房屋中介的作用就是在房地产开发经营与消2 o M 1 j c h f费的供求市场中,% 3 N k G H m K为交易物体提供评估t Z / l ( m 7 ` B、交易、代理、咨询等服务及善后服务的机构。
结合案j a A ; 8 } * A P例理解代理模式的定义
在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理模式就是为其他用户提供一X = ) ) # . \ M种代理,用户不用知道买房的具体过程,而用户应该关心的是如何获得满意的结果
,代理所需要做的事情就是完成这一买房的过程
。
什么是Pr0 I _ Q _ joxy
Proxy用于修改w & . X某些操作的默认行为,在目标对象前架设一个
“拦截”层
,外界对该6 z 7 u T X对1 O Z ! v A m 0 f象的访问都必须N V E P ; ; ) t e先通过这一R K 9 & ( : * P层拦截,因此提供了一种机制可以对外界的访问进行过滤和改写。——《ES6标准入门》- 第12章
Proxy支持的拦截操作有许多中,目前只针对get(target, propKey, receive$ G \ ) ur)和set(target9 p v }, propKey, value, receiver)来讲N V p。
- get方法:拦截对象属性的读取;
- set方法:拦截对象属性的W ) b N f i设置。
get} ( V 7 5(target, propKey, receiver)
定义一个Persq 1 Y @ } [ & [on对象,它将被Proxy代理,外界通Proxy实例对象来访问Person对象。
var person = {
name: "kongsam",
age: 21,
hS $ F b robbies: [
"看动漫",
"骑行",
"玩游戏"
]
}z 4 !
实例化一个Proxy对象,用于拦截外界对Peb _ i a p P |rson对象的操作。
var proxy = new Proxy(person, {
get: function (target, property) {
// 打印target和propertb T v Q ; k [ F 1y,查看里面到底是什么。
console.log(O { k \"target = ", target);
console.log("property = ", property);
// 判断外界访问的3 i [ ] r对象属性是否存在于目标对象中。
if (property in target) {
return target[property];
} else {
/w ; x k g/ 如果外界访问的对S G A n T j $象属性不存在与目标对象中,抛出异常。
throw new Refereng E & q [ j b (ceError('Prob 5 x ~ k $ 1 $perty "' + property + '" 不存在。');
}
},
});
当进行proxy.name
操作时,由于Person对象已经被Proxy代7 9 # / 6理了,所以每当我通过该Proxy实例对象访问Person中存在
的属性时,都会调用get方法,get方法是拦截对象属性的读取的。
get: functio\ # I Gn (target, propA . N r & 7 G \erty) 中的两个参数target和property分别接收到的信息如图所示
通过该代理对象访问Person对象中存在? W | b s z的属性不会出现任何异常,如果访问不存在的属性会发生什么t d e o K 4 z y?Y | ] u
是什么,以至于访问不存在的属性时,它会抛出异常呢?
这是因为外界对Person对象的访问都必须先通过Proxy设置的拦截层% G v,而拦截层提供了一种机制可以对外界的访问进行过滤和改写。
// 判断外界访问的对象属性是否存在于目标对象中。
if (prn f poperty in target) {
return target[property];
} else {
// 如果外界访问的对象属性不存在与目标对象中,抛出异常。
throw new Refere5 p 0 # H (nceError('Property "' + property + '" 不存在。');
}
if语句就是拦截层的具体操作,即对外界的访问进行过滤和改写。如果没有,访问不存在的属性就会返回undefined。
set(target, propKey, value, receiver)
依旧是Person对象,这时我有个新需求,即修改age属性时,值t \ ?不能超过150且是整数。
新增Proxy= ^ I ] ) B J d对象中` v 5 P h w W M B的set方法。
var proxy = new Proxy(peW [ Y i ; O | Srson, {
set: functioni d S 2 S (target, property, vC Y P A @ _ [ }alue) {
// 打印target、property和value,A ; 6 i Y _查看里面到底是什么。
console.log("tV Q r _ t $arget = ", target);
console.loo [ 4g("property = ", property);
console.log("value = ",w m T 2 ! { valued ! S } l n);
if (property === "age") {
if (!Number^ t _ 3 1 1 e ^.isInteger(value)) {
throw new TypeError("age的值不是整数!");
}
if (val i ilue > 150) {
throw neY P $ B ] 4w RangeError("age的值不能大于150!");\ w p
}
}
},
});
当我执行proxy.age = 100
时,set的三个参数分别接收到的信息如下图} 8 c j I 2 b所示。
set方法用于拦截某个属性的赋值操作,我如果对age的赋值操作不满= @ K # 3足条件时,会发生什么?
很明@ H \ ] d o V显,会抛出异常。
总结
Proxy就是拦截层,你给出被拦截的对象,外界访问这个对象} s H N E % 5 Y必须先通过拦截层,即访问ProU x # A j Q Kxy的实例对象。通过Proxy为外界访问进行过滤b d ] P T L 6 &和改写,如赋值时需满足某些条件。
代理对象中还有许多的方法,如has、deleteProperty、ownKeys、getOwnPropertyDescriptor等,都是用于拦截不同的情况而出现的。