前言
本文主要讲解代理与反射,那么好,本文正式开始。
代理
代理基础
代理是目标对象的替身,同时它又独立于目标对象,意思就是说,我们在操作对象的时候,直接操作或通过操作代理的方式间接操作目标对象。
创建空代理
使用proxy构造函数创建代理,proxy有两个必要参数:
1,目标对象。2.处理程序
语法格式:const proxyObj=new Proxy(target,handle)
举例:
const obj={id:"target"};
const handle={}
const proxy=new Proxy(obj,handle)
console.log(obj.id,proxy.id);//target target
obj.id='tar'
console.log(obj.id,proxy.id);//tar tar
console.log(obj.hasOwnProperty('id'),proxy.hasOwnProperty('id'));//true true
// console.log(obj instanceof object,proxy instanceof Proxy);
console.log(obj===proxy);//false
在上述代码中,实现了一个简单的代理,这里用的程序处理handle为空,我们既可以用obj.id也可以用proxy.id都能得到target这个值。
可以用hasOwnProperty
检测出对象的具体属性
Proxy.prototype
是 undefined
,因为 Proxy 是一个构造函数,它的原型对象是通过 Object.create(null)
创建的。这意味着 Proxy.prototype
没有继承自任何其他对象,因此它是独立的。
可以用严格相等检测出代理和目标对象的不同。
定义捕获器
捕获器是代理的重要概念之一,它作用是可以在设置捕获的某个路径中进行程序处理。实现捕获。
举例:比如我们想要让目标对象输出时候输出1.
const obj={id:"target"}
const handle={
get(){
return 1;
}
}
const proxy=new Proxy(obj,handle)
console.log(obj.id,proxy.id);//target 1
捕获器参数和反射API
每个捕获器都有参数,这里拿get举例,get捕获器有三个参数:
1.目标对象2.要查询属性3.代理对象
那么我们就可以基于它的这些参数特性,去二次封装它们的捕获器。
const obj={id:'target'}
const handle={
get(target,prototype,proxy){
console.log(target === obj);//true
console.log(prototype);// id
console.log(proxy);//Proxy(Object) {id: 'target'}
return 1;
}
}
const proxy=new Proxy(obj,handle)
console.log(proxy.id);
当我们知道一个捕获器的原始参数后,就可以封装,如果我们不知道原始参数时,可以用到全局Reflect方法,Reflect有和被拦截方法相同的名称和行为。
const obj={id:'target'}
const handle={
get(){
return Reflect.get(...arguments)
}
}
const simplehandle={
get:Reflect.get
}
const proxy=new Proxy(obj,handle)
const simpleProxy=new Proxy(obj,simplehandle)
const bestProxy=new Proxy(obj,Reflect)
console.log(proxy.id,simpleProxy.id,bestProxy.id);//target target target
捕获器不变式
捕获器为了避免出现过于反常行为,引入了不变式的概念。在使用程序处理中,必须遵循不变式的条件。否则将报错,比如目标对象有一个不可配置且不可写的属性,捕获器返回一个不同值时,报错TypeError。
const obj={}
Object.defineProperty(obj,'id',{
configurable:false,
writable:false,
value:'target'
})
const handle={
get(){return 'tar'}
}
const proxy=new Proxy(obj,handle)
console.log(proxy.id);//Uncaught TypeError:
可撤销代理
为了让代理有足够自由度,同时我们也可以通过revocable()函数实现对代理的撤销,撤销后,代理将失去它原有的作用。
const obj={id:"target"}
const handle={
get(){return 'tar'}
}
const {proxy,revoke}=Proxy.revocable(obj,handle)
console.log(proxy.id);//tar
revoke()
console.log(proxy.id);//ncaught TypeError: Cannot perform 'get' on a proxy that has been revoked
实用反射API
- 反射API与对象API
- 反射API不限于只应用在捕获程序中。
- 大多数反射API方法在Object类型中都有对应的方法。
- 反射API方法部分有状态标记,也就是说它能判断是否生效。
Reflect.defineProperty()
Reflect.preventExtensions()
Reflect.setPrototypeOf()
Reflect.set()
Reflect.deleteProperty()
以上方法都提供状态标记。
代理另一个代理
可以通过一个双重代理来代理目标对象,也就是经过两次程序处理。
举例:
const obj={id:'target'}
const handle={
get(){
console.log('first');
return Reflect.get(...arguments);
}
}
const firstProxy=new Proxy(obj,handle)
const secondHandle={
get(){
console.log('second');
return Reflect.get(...arguments);
}
}
const secondProxy=new Proxy(firstProxy,secondHandle);
console.log(secondProxy.id);//second first target
反射
代理捕获器与反射方法
代理可以捕获13中不同操作。
get()
get方法会在获取属性值时被调用,对应的反射方法是Reflect.get()
语法格式:Reflect.get(proxy, property, receiver)
set()
set方法会在更新属性值时被调用,对应的反射方法是Reflect.set()
语法格式:Reflect.set(proxy, property, value, receiver)
has()
has方法会在in操作符中被调用,主要判断左侧属性是否在右侧对象中,对应的反射方法是Reflect.has()
const obj={id:'target'}
const handle={
has(){
console.log('has()');
return Reflect.has(...arguments)
}
}
const proxy=new Proxy(obj,handle)
console.log('id' in proxy);//has() true
还有像defineProperty、getOwnPropertyDescriptor、deleteProperty、ownKeys、getPrototypeOf、setPrototypeOf、isExtensible、preventExtensions、apply、construct等方法,这里就不一一赘述了,这些方法都可以被捕获(劫持)并且可以二次封装。
代理模式
跟踪属性访问
可以监控属性何时或何处被访问,可以通过劫持get、set或has方法来实现,举例:
const obj={id:'target'}
const handle={
get(target,a,proxy){
console.log("被调用",a);
return Reflect.get(...arguments);
}
}
const proxy=new Proxy(obj,handle)
console.log(proxy.id);// 被调用 id target
隐藏属性
可以通过数据劫持后判断是否显示某个属性,如果不显示,则实现隐藏效果。举例:
const obj={id:'target',age:18}
const hidden=['age']
const handle={
get(target,a,proxy){
if(hidden.includes(a)){
return undefined;
}else{
return Reflect.get(...arguments)
}
},
has(target,a,proxy){
if(hidden.includes(a)){
return false;
}else{
return Reflect.get(...arguments)
}
}
}
const proxy=new Proxy(obj,handle)
console.log(proxy.id,proxy.age);//target undefined
console.log('id' in proxy,'age' in proxy);//true false
属性验证
可以判断验证属性格式是否正确,举例:
const obj={age:18}
const handle={
set(target,property,value){
if(typeof value!=='number'){
return false;
}else{
return Reflect.set(...arguments);
}
}
}
const proxy=new Proxy(obj,handle)
proxy.age='1'
console.log(proxy.age);//18
proxy.age=1
console.log(proxy.age);//1
数据绑定
可以把一个数据绑定到另一个数据中,实现强关联。举例:文章来源:https://www.toymoban.com/news/detail-764471.html
const arr=[]
class user{
constructor(name){
this.name_=name
}
}
const handle={
construct(){
const newUser=Reflect.construct(...arguments);
arr.push(newUser);
return newUser;
}
}
const proxy=new Proxy(user,handle);
new proxy('Hellon');
console.log(arr);//[user]
总结
代理就是对数据的劫持,并且劫持的过程中加一些操作,反射,就是对象方法的复制API。可以从头到尾复刻对象的某个API方法。以上就是,全部内容。文章来源地址https://www.toymoban.com/news/detail-764471.html
到了这里,关于JavaScript红宝书第九章:代理与反射的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!