当前位置:网站首页>代理与反射(二)
代理与反射(二)
2022-06-12 02:07:00 【赤蓝紫】
代理与反射(二)
使用代理模式可以实现一些有用的功能。
捕获操作
通过添加对应捕获器,就可以捕获get、set、has等操作,可以监控这个对象何时在何处被访问过,并且能在访问、修改前干想干的事,并通过反射重新实现原功能。
const user = {
name: 'clz'
}
const proxy = new Proxy(user, {
get(target, property, receiver) {
console.log(`访问 ${
property}`)
return Reflect.get(...arguments)
},
set(target, property, value, receiver) {
console.log(`设置 ${
property}=${
value}`)
return Reflect.set(...arguments)
}
})
console.log(proxy.name)
proxy.age = 21

这里有一个需要小小注意的点:通过代理对象的操作才会被捕获,而直接操作目标对象的操作不会被捕获。
const user = {
name: 'clz'
}
const proxy = new Proxy(user, {
get(target, property, receiver) {
console.log(`访问 ${
property}`)
return Reflect.get(...arguments)
}
})
console.log(proxy.name)
console.log(user.name)

隐藏属性
因为代理的内部实现对于外部的代码来说是不可见的,所以想要隐藏目标对象上的属性也很容易实现。我们上面说过,需要通过反射来实现原功能,但是我们也可以不实现原功能,而是返回其他值。
const user = {
name: 'clz',
age: 21
};
const proxy = new Proxy(user, {
get(target, property, receiver) {
if (property === 'name') {
// 隐藏name属性
return undefined;
}
return Reflect.get(...arguments)
}
});
console.log(user)
console.log(user.name)
console.log(user.age)
console.log('%c%s', 'font-size:24px;color:red', '=================')
console.log(proxy)
console.log(proxy.name)
console.log(proxy.age)

从上图,我们可以知道,直接访问目标对象、目标对象属性以及访问代理对象都能能到一样的结果。但是,通过代理访问 name属性会得到 undefined,因为我们在捕获操作中进行了隐藏属性。
验证
属性验证
因为所有的赋值操作都会触发set捕获器,所以可以根据所赋的值决定是允许还是拒绝赋值,不通过验证,直接return false即可拒绝赋值。
const user = {
name: 'clz',
age: 21
};
const proxy = new Proxy(user, {
set(target, property, value) {
if (typeof value !== 'number') {
console.log('不是number类型,拒绝赋值')
return false;
} else {
return Reflect.set(...arguments);
}
}
});
proxy.age = 999;
console.log(proxy.age);
proxy.age = '111';
console.log(proxy.age);

当我们返回 false时,即不通过验证,就可以不进行原始行为的实现,
函数参数验证
和验证对象属性类似,也可以对函数的参数进行审查。
首先,函数也是能使用代理的。apply捕获器会在调用函数时被调用。
function fn() {
}
const proxy = new Proxy(fn, {
apply() {
console.log('调用函数')
}
});
proxy(1, 2, 3, 4, 5)
所以我们应该在 apply捕获器中进行操作验证。
function mysort(...nums) {
return nums.sort((a, b) => a - b);
}
// 在`apply`捕获器中进行参数验证
const proxy = new Proxy(mysort, {
apply(target, thisArg, argumentsList) {
// target: 目标对象
// thisArg: 调用函数时的this参数
// argumentsList: 调用函数时的参数列表
for (const arg of argumentsList) {
if (typeof arg !== 'number') {
throw '函数参数必须为number';
}
}
return Reflect.apply(...arguments);
}
});
let fin = proxy(2, 1, 6, 3, 4, 3);
console.log(fin);
fin = proxy(2, 1, 'hello', 3, 4, 3);
console.log(fin);
构造函数同理,只是构造函数是通过constructor捕获器来实现代理。
function Person(name) {
this.name = name
}
const proxy = new Proxy(Person, {
construct() {
console.log(123)
return Reflect.construct(...arguments)
}
});
const p = new proxy('clz')
console.log(p)
数据绑定
通过代理可以把原本运行中不相关的部分联系到一起。
例子:将被代理的类绑定到一个全局的实例集合,将所有创建的实例都添加到这个集合中。`
const userList = []
class User {
constructor(name) {
this.name_ = name;
}
}
const proxy = new Proxy(User, {
construct() {
const newUser = Reflect.construct(...arguments)
userList.push(newUser)
return newUser
}
})
new proxy('clz')
new proxy('czh')
console.log(userList)
事件分发程序
在开始之前,先来一个小问题。
const nums = []
const proxy = new Proxy(nums, {
set(target, property, value, receiver) {
console.log('setting')
return Reflect.set(...arguments)
}
})
proxy.push(1)
上面的代码会打印两次setting。
这是为什么呢?
让我们把它每一轮修改的属性打印出来,研究一下。
const nums = []
const proxy = new Proxy(nums, {
set(target, property, value, receiver) {
console.log('setting')
console.log(property)
return Reflect.set(...arguments)
}
})
proxy.push(1)

我们可以发现,第一次是0,第二次是 length。也就是说,push实际上是分成两个阶段的,第一轮先修改数组,第二轮再修改数组长度,所以会打印两轮。(没有找到权威的解释,实践测试得出的结论,有问题可评论)
回到正题:可以把集合绑定给一个事件分发程序,实现每次插入新实例时,都会发送消息。
const nums = []
function emit(newValue) {
console.log('有新数据,新数据是', newValue)
}
const proxy = new Proxy(nums, {
set(target, property, value, receiver) {
const result = Reflect.set(...arguments)
// Reflect.set返回boolean值,该值指示该属性是否已成功设置
if (result) {
// 如果被成功设置了,调用事件分派函数,把新插入的值作为参数传过去
emit(Reflect.get(target, property, receiver))
}
return result
}
})
proxy.push(111)
proxy.push(222)
console.log(proxy)

这里可以发现,我们 push两条数据,但是会触发事件分发程序4次,这是为什么?
这就是这一小节上面讲的,push实际上是分成两个阶段的,第一轮先修改数组,第二轮再修改数组长度。
所以,我们不应该只是判断是否被成功设置,还应该判断属性是不是 length。
if (result && property !== 'length') {
// 如果被成功设置了,调用事件分派函数,把新插入的值作为参数传过去
emit(Reflect.get(target, property, receiver))
}

边栏推荐
- [adjustment] notice on the opening of the 2022 pre adjustment system for postgraduate enrollment of Shanghai Second University of Technology
- 初探性能优化!从2个月到4小时的性能提升!
- Niuke monthly race 14- simple counting
- 力扣解法汇总449-序列化和反序列化二叉搜索树
- 入手Ticwatch2
- “中国东信杯”广西大学第四届程序设计竞赛(同步赛)
- 力扣解法汇总-04.06. 后继者
- Knowledge points of mall development
- Bracket generation (backtracking)
- Advantages of Google ads
猜你喜欢

Glfwpollevents() program crash
![[adjustment] notice on the opening of the 2022 pre adjustment system for postgraduate enrollment of Shanghai Second University of Technology](/img/16/2f9a235995cdd54ac9b85a68a7afcb.jpg)
[adjustment] notice on the opening of the 2022 pre adjustment system for postgraduate enrollment of Shanghai Second University of Technology

Knowledge points of mall development

Installing MySQL version 5.5 database for Linux (centos6)

leetcode:6. Zigzag transformation

Smartbi helps you solve the problem of losing high-value customers
![[adjustment] in 2022, the Key Laboratory of laser life sciences of the Ministry of education of South China Normal University enrolled adjustment students in optics, electronic information, biomedicin](/img/f9/332b206d5aca0ca6afc3fdf11a53c8.jpg)
[adjustment] in 2022, the Key Laboratory of laser life sciences of the Ministry of education of South China Normal University enrolled adjustment students in optics, electronic information, biomedicin

Subject knowledge and educational ability of information technology in the first half of 2019 – subjective questions

Linux(CentOS6)安装MySQL5.5版本数据库

如何让杀毒软件停止屏蔽某个网页?以GDATA为例
随机推荐
力扣解法汇总427-建立四叉树
Operating mechanism of Google ads bidding
力扣解法汇总1037-有效的回旋镖
通过搜索广告附加信息让广告更具相关性
Explore performance optimization! Performance improvement from 2 months to 4 hours!
阿里云oss文件上传系统
Metaverse × How will smart cities develop?
力扣解法汇总944-删列造序
力扣解法汇总473-火柴拼正方形
超图倾斜数据合并根节点后转3dtiles
Leetcode 55 jump game
国资入股,建业地产这回稳了吗?
State owned assets into shares, has Jianye real estate stabilized?
程序员应该如何解决买菜难问题?手把手带你利用无障碍辅助功能快速下单抢菜
How to locate keywords to make advertising accurate.
没有文笔,大家多多包涵
MySQL advanced knowledge points
Pagination writing of PHP security open 10 article list module
Master of a famous school has been working hard for 5 years. AI has no paper. How can the tutor free range?
广泛匹配修饰符符号已经被弃用,请勿使用