当前位置: 首页 > news >正文

代理与反射

Proxy(代理器)

用于修改某些操作的默认行为。

在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截。

new Proxy(target,handler)

拦截操作

Proxy支持的拦截操作一共13种。

拦截操作拦截行为
get(target, propKey, receiver)
拦截对象属性的读取,比如proxy.foo和 proxy['foo']
set(target, propKey, value, receiver)
拦截对象属性的设置,比如 proxy.foo = v或proxy['foo'] = v,返回一个布尔值
has(target, propKey)
拦截propKey in proxy的操作,返回一个布尔值
deleteProperty(target, propKey)
拦截delete proxy[propKey]的操作, 返回一个布尔值
ownKeys(target)
拦截Object.getOwnPropertyNames(proxy)、 Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for...in循环, 返回一个数组。该方法返回目标对象所有自身的属性的属性名,而 Object.keys()的返回结果仅包括目标对象自身的可遍历属性
getOwnPropertyDescriptor(target, propKey)
拦截 Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象
defineProperty(target, propKey, propDesc)
拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值
preventExtensions(target)
拦截Object.preventExtensions(proxy),返回一个布
尔值
getPrototypeOf(target)
拦截Object.getPrototypeOf(proxy),返回一个对象
isExtensible(target)
拦截Object.isExtensible(proxy),返回一个布尔值
setPrototypeOf(target, proto)
拦截Object.setPrototypeOf(proxy, proto),返回
一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截
apply(target, object, args)
拦截 Proxy 实例作为函数调用的操作,比如 proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)
construct(target, args)
拦截 Proxy 实例作为构造函数调用的操作,比如new
proxy(...args)

同一个拦截器对象,可以设置拦截多个操作。

Proxy构造函数

ES6原生提供Proxy构造函数,用来生成Proxy实例。

let obj = new Proxy({},{get: function (target, key, receiver) {console.log(`getting ${key}`);return Reflect.get(target, key, receiver);},set: function (target, key, value, receiver) {console.log(`setting ${key}`);return Reflect.set(target, key, value, receiver);},}
);
obj.count = 1;
++obj.count;
console.log(obj);
//输出
// setting count
// getting count
// setting count
// { count: 2 }

handler,拦截器对象,包含了一个或多个陷阱函数。

拦截读取属性行为

const person = {name: "Jhon",
};
const proxy = new Proxy(person, {get(target, property) {if (property in target) {return target[property];} else {throw new ReferenceError(`Property "${property}" does not 
exist.`);}},
});
console.log(proxy.name); // Jhon
console.log(proxy.age); // Property "age" does not exist.

拦截设置属性行为

const person = {name: "Jhon",age: 30,
};
const handler = {set(target, property, value) {if (property === "age" && typeof value !== "number") {throw new TypeError("The age property must be a number.");}Reflect.set(target, property, value);},
};
const proxy = new Proxy(person, handler);
proxy.age = 31; // 成功
console.log(proxy);
console.log(person);
proxy.age = "thirty-one"; // TypeError: The age property must be a number.

如果handle没有设置任何拦截,就等于直接通向源对象。

let target = {};
let handler = {};
let p = new Proxy(target, handler);
p.a = "b";
console.log(target, p.a);//b
target.a = "bb";
console.log(target, p.a);//bb

应用

对象属性的操作:getsetdeletejs特有)。

对象的属性名只有两种数据类型:字符串string、字符symbol

保持对象结构

const handler = {get(target, property) {if (property in target) {return Reflect.get(target, property);} else {throw new ReferenceError(`Property "${property}" does not exist.`);}},set(target, property, value) {if (property in target) {Reflect.set(target, property, value);} else {throw new ReferenceError(`Property "${property}" does not 
exist.`);}},
};
const person = {name: "Jhon",age: 30,showMe() {console.log(`${this.name}, ${this.age}`);},
};
const proxy = new Proxy(person, handler);
console.log(proxy.name, proxy.age); // Jhon, 30
proxy.showMe(); // Jhon, 30
proxy.gender = "male";

实现数组读取负数索引

const names = ["Jhon", "Tom", "Mary", "Lucy"];
const handler = {get(target, property) {const index = Number(property);if (isNaN(index)) {return Reflect.get(target, property);} else {return target[(index + target.length) % target.length];}},
};
const proxy = new Proxy(names, handler);
console.log(proxy[-1]); // Lucy

利用get陷阱实现DOM节点生成器

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Proxy</title></head><body></body><script>const dom = new Proxy({},{get(target, property) {return function (attrs = {}, ...children) {const el = document.createElement(property);for (let prop of Object.keys(attrs)) {el.setAttribute(prop, attrs[prop]);}for (let child of children) {if (typeof child === "string") {child = document.createTextNode(child);}el.appendChild(child);}return el;};},});const el = dom.div({},"Hello, my name is ",dom.a({ href: "http://www.example.com" }, "Mark"),". I like:",dom.ul({},dom.li({}, "The web"),dom.li({}, "Food"),dom.li({}, "...actually that's it")));document.body.appendChild(el);</script>
</html>

基于class的代理器

class Person {constructor(name, age) {this.name = name;this.age = age;return new Proxy(this, {get(target, property) {if (property in target) {return target[property];} else {throw new ReferenceError(`Property "${property}" 
does not exist.`);}},});}
}
const person = new Person("Jhon", 30);
console.log(person.name); // Jhon
console.log(person.age); // 30
console.log(person.gender); // 抛出 ReferenceError

Reflect(反射)

提供了统一的反射接口,给底层操作提供了默认行为的方法合集。

每个代理陷阱都有一个对应的反射方法,每个方法都与之对应的陷阱函数同名,并且接收一致的参数。

代理陷阱

13种代理陷阱

代理陷阱被重写的行为默认行为
get
读取一个属性的值
Reflect.get( )
set
写入一个属性
Reflect.set( )
has
in运算符
Reflect.has( )
apply
调用一个函数
Reflect.apply( )
construct
使用new调用一个函数
Reflect.construct( )

ownKeys

Object.keys( )
Object.getOwnPropertyNames( )
Object.getOwnPropertySymbols( )
Reflect.ownKeys( )
.........

http://www.lqws.cn/news/557407.html

相关文章:

  • 基于LQR控制器的六自由度四旋翼无人机模型simulink建模与仿真
  • 微软人工智能证书AI-102 | 如何快速通过?
  • 桌面小屏幕实战课程:DesktopScreen 16 HTTP
  • 【软考--软件设计师】11 关系型数据库
  • WebRTC(十二):DTLS
  • 关于前端页面上传图片检测
  • 暑假复习篇之运算与逻辑
  • UI前端大数据可视化创新:利用AR/VR技术提升用户沉浸感
  • 什么是集中刷新,分散刷新,和异步刷新
  • 从 AJAX 到 axios:前端与服务器通信实战指南
  • 2023国赛linux的应急响应-wp
  • Re--攻防世界-基础android
  • C++ vector 完全指南:从入门到精通
  • 源码运行效果图(六)
  • 【HarmonyOS Next之旅】DevEco Studio使用指南(三十八) -> 构建HAR
  • 基于springboot的海产品交易系统
  • 【数据标注师】3D标注
  • JWT认证性能优化实战指南
  • 《从 0 到 1 掌握正则表达式:解析串口数据的万能钥匙》
  • springboot+Vue逍遥大药房管理系统
  • 创建套接字时和填充地址时指定类型的异同
  • C++泛型编程2 - 类模板
  • 【数论】P11169 「CMOI R1」Bismuth / Linear Sieve|普及+
  • 嵌入式硬件与应用篇---寄存器GPIO控制
  • 进阶向:Flask框架详解,从零开始理解Web开发利器
  • Odoo邮箱别名使用指南:从配置到业务流程自动化
  • C# 委托(为委托添加方法和从委托移除方法)
  • docker部署后端服务的脚本
  • Golang JSON 标准库用法详解
  • Foundry测试实战:解锁区块链测试新姿势