JS 代理第一篇:在代理中使用反射

理解代理的概念

有过 java 或者 c# 经验的同学,比较容易理解代理的概念和作用,可以类比类中的 setter 和 getter
没有相关经验,读完下面内容,也可以初步理解JS中的代理了
有下面一个对象

const duck = {
    name: 'Maurice',
    color: 'white',   
}

我们可以像下面这样操作对象中的属性

// 获取属性
duck.name
// 设置属性
duck.name = 'John'

但是如果我们有其他要求,上面的方式就很难满足了,如

  • 限制name属性的赋值,如长度必须为10个字符以下
  • 获取属性时,希望加上额外的内容

这时候就可以使用代理
具体用法是,为目标对象(duck)定义一个关联的代理对象,而这个代理对象可以作为抽象的目标对象来使用,在对目标对象的各种操作影响到目标对象之前,可以在代理对象中对这些操作加以控制
下面通过案例讲解上面的内容

创建代理对象

首先通过空代理理解代理的概念
首先创建一个对象

// 获取属性
duck.name
// 设置属性
duck.name = 'John'

然后创建一个代理对象,并通过代理对象操作目标对象的属性

const duck = {
    name: 'Maurice',
    color: 'white',   
}
// 创建代理对象
const handler={}
// 创建代理
const proxy = new Proxy(duck,handler)
// 通过代理获取属性
console.log(proxy.name);
// 通过代理为属性设置值
proxy.name = 'John'
console.log(proxy.name);

上面创建的是一个空的代理对象,即代理对象中没有任何捕获器

定义捕获器

创建代理的主要目标就是可以定义捕获器,每个代理对象中可以定义0个或多个捕获器
捕获器就是拦截器,当通过代理访问目标对象的属性或者方法时,当这些操作传播到目标对象之前,捕获器就会先调用,从而拦截修改相应的代码
下面定义一个 get 捕获器,当通过proxy[property]proxy.property等方式访问目标对象属性时,就会触发 get 捕获器

image.png

上面的get不获取返回了固定内容’hello’,所以当通过代理访问任何一个属性时,返回的值都是 hello
我们希望访问不同的属性,get 捕获器中就不能返回固定值,这个可以通过捕获器参数实现,也可以通过后面说的反射实现

捕获器参数

所有捕获器都可以访问相应的参数,比如 get 捕获器可以接受目标对象、要查询的属性和代理对象三个参数

image.png

这里要记住,三个参数分别是

  • 目标对象:也就是设置代理的对象 duck
  • 要查询的属性,也就是第17行中,通过代理访问的目标对象的属性 name
  • 代理对象

这里重点理解前两个参数,这对于理解后面的反射代码很有帮助

将 get 捕获器修改如下,就可以做到,访问什么属性,就返回什么属性的值

const duck = {
    name: 'Maurice',
    color: 'white',   
}
// 创建代理对象
const handler={
    get(trapTarget,property,receiver){
        // 重点是这里
        return trapTarget[property]
    }
}
// 创建代理
const proxy = new Proxy(duck,handler)
// 通过代理访问目标对象属性时,首先会被get捕获器拦截,捕获器其实就是一个函数,函数的返回值就是 prox.property的返回值
console.log(proxy.name); // Maurice
console.log(proxy.color); // white

为什么使用代理

看到上面的代码,有些人难免有所疑惑,直接访问对象的属性不香吗?为什么一定要套一层代理呢?
其实,get 捕获器本身就是函数,我们自然可以在函数中编写代码,对属性的访问进行控制,这一点通过 set 捕获器应该更容易理解
set 捕获器会在设置属性值的操作中被调用,接受四个参数

  • 目标对象
  • 设置值的属性
  • 设置的值
  • 代理对象

image.png

通过上面的代码,大家就理解了,在代理的捕获器中可以对值进行控制,而通过目标对象直接为属性设置值,是无法控制的

duck.age=200 // 无法进行控制

反射的应用

反射的概念在如 java、c# 等语言中早已存在

反射的核心概念是在程序运行当中,对于任何一个类,都知道这个类的所有属性和方法;对于任何一个对象,都能够调用它的任意属性和方法

这里的关键之处在于程序运行当中可以获取对象的属性或者方法,如果没有实际的应用场景,就很难理解反射的概念,这里先掌握住反射的用法即可

这里只简单学习 get 方法的使用

**Reflect.get()**方法与从 对象 (target[propertyKey]) 中读取属性类似,但它是通过一个函数执行来操作的。

const duck={
    name:'Mary'
}

console.log(Reflect.get(duck,'name'));

上面代码从对象 duck 中读取属性 name 的值,并作为函数的返回值

image.png

如果你对展开运算符和函数参数 arguments 了解的话,上面划线的代码改成这样也是可以的

image.png

代码可以再简单一点

image.png

总结

至此,我们对代理的基本概念和使用,以及反射的基本概念和使用有了一个初步的了解,这是后续学习的重要基础

© 版权声明
THE END
喜欢就支持一下吧
点赞10 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容