理解代理的概念
有过 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 捕获器
上面的get不获取返回了固定内容’hello’,所以当通过代理访问任何一个属性时,返回的值都是 hello 我们希望访问不同的属性,get 捕获器中就不能返回固定值,这个可以通过捕获器参数实现,也可以通过后面说的反射实现
捕获器参数
所有捕获器都可以访问相应的参数,比如 get 捕获器可以接受目标对象、要查询的属性和代理对象三个参数
这里要记住,三个参数分别是
- 目标对象:也就是设置代理的对象 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 捕获器会在设置属性值的操作中被调用,接受四个参数
- 目标对象
- 设置值的属性
- 设置的值
- 代理对象
通过上面的代码,大家就理解了,在代理的捕获器中可以对值进行控制,而通过目标对象直接为属性设置值,是无法控制的
duck.age=200 // 无法进行控制
反射的应用
反射的概念在如 java、c# 等语言中早已存在
反射的核心概念是在程序运行当中,对于任何一个类,都知道这个类的所有属性和方法;对于任何一个对象,都能够调用它的任意属性和方法
这里的关键之处在于程序运行当中可以获取对象的属性或者方法,如果没有实际的应用场景,就很难理解反射的概念,这里先掌握住反射的用法即可
这里只简单学习 get 方法的使用
**Reflect.get()
**方法与从 对象 (target[propertyKey]
) 中读取属性类似,但它是通过一个函数执行来操作的。
const duck={name:'Mary'
}
console.log(Reflect.get(duck,'name'));
上面代码从对象 duck 中读取属性 name 的值,并作为函数的返回值
如果你对展开运算符和函数参数 arguments 了解的话,上面划线的代码改成这样也是可以的
代码可以再简单一点
总结
至此,我们对代理的基本概念和使用,以及反射的基本概念和使用有了一个初步的了解,这是后续学习的重要基础
最后
最近还整理一份JavaScript与ES的笔记,一共25个重要的知识点,对每个知识点都进行了讲解和分析。能帮你快速掌握JavaScript与ES的相关知识,提升工作效率。
有需要的小伙伴,可以点击下方卡片领取,无偿分享