代理与Reflect反射

属性描述符

Proprety Descriptor 属性描述符 用于描述一个属性的相关信息

1.Object.getOwnPropertyDescriptor(对象,属性名)

可以得到一个对象的 某个属性的属性描述符 

  Object.getOwnPropertyDescriptors(对象)

 可以得到某个对象的所有属性描述符

如果需要为某个对象添加属性或修改属性时,配置其属性描述符,可以使用

Object.definePropertie(对象、属性、描述符 )

Object.definePropertie(obj, 'a', { configurable: false })

 存取器属性

  • 属性描述符中,如果配置了get  set中任何一个,则该属性不再是一个普通属性,而变成存储器属性
  • get、set配置均为函数,如果一个属性是存储器属性,则读取该属性时,会运行get方法,将get方法得到的返回值作为属性值
  • 如果给该属性赋值,则会运行set方法
  • 存取器属性最大的意义,在于可以控制属性的读取和赋值
const obj = {b: 1
}
Object.defineProperty(obj, 'a', {get () {console.log("运行了属性的get函数")}, set (val) {console.log("运行了属性的set函数", val)}
})
obj.a = obj.a + 1 
//set(obj.a+1) ==>set(get()+1)  
//1.需要先读取a值,但get()没有返回值 因此是undefined 
//2.undefined+1=NaN 
console.log(obj.a)

 

 1.使用其他属性值赋值。也可新增属性  _a

const obj = {b: 1
}
Object.defineProperty(obj, 'a', {get () {console.log("运行了属性的get函数")return obj._a //使用其他属性值}, set (val) {console.log("运行了属性的set函数", val)obj._a = val}
})
obj.a = 10 
console.log(obj.a)

 2.也可对赋值做自定义规范

Object.defineProperty(obj, 'a', {get () {console.log("运行了属性的get函数")return obj._a}, set (val) {if (typeof val !== 'number') {throw new TypeError('必须是一个数字')}if (val > 200) {val = 200}console.log("运行了属性的set函数", val)obj._a = val}
})
obj.a = 10000

Reflect 

1.reflect是什么?

reflect是一个内置的JS对象,它提供了一系列方法,可以让开发者通过调用这些方法,访问一些JS底层功能

由于类似于其他语、言的【 反射】,因此取名为Reflect

2.可以做什么?

可以实现 属性的赋值与取值、调用普通函数、调用构造函数、判断属性是否存在于对象中.etc

3.为什么还需要Reflect实现一次已有功能?

ES5提出重要理念  “减少魔法、让代码更加纯粹”,其很大程度受函数式编程影响

ES6进一步贯彻了该理念,它认为,对属性内存的控制、原型链的修改、函数的调用等,都属于底层实现,属于一种魔法,因此需要将他们提取出来形成一个正常的API ,高聚合到某个对象中,于是,造就了Reflect对象

4.提供了哪些API?

代理:Proxy

代理:提供了修改底层实现的方式

new Proxy(target,handler)

  • 代理一个目标
  • target:目标对象
  • handler:是一个普通对象,其中可以重写底层实现
  • 返回一个代理对象
const obj = {a: 1,b: 2
}
const proxy = new Proxy(obj, {set (target, propertyKey, value) {Reflect.set(target, propertyKey, value)},get (target, propertyKey) {if (Reflect.has(target, propertyKey)) {return Reflect.get(target, propertyKey)} else {return -1}},has (target, propertyKey) {return false}
})
proxy.a = 10
console.log(proxy.a)
console.log(proxy.d)

proxy应用——观察者模式

有一个对象,是观察者,他用于观察另外一个对象的属性值变化,当属性值变化后会收到一个通知,可能会做一些事 

以下方式不太好

function observer (target) {const ob = {}const div = document.getElementById('container')const props = Object.keys(target)for (const prop of props) {Object.defineProperty(ob, prop, {// 读属性值时,把目标值给你get () {return target[prop]},// 赋值时,给目标对象赋值,再渲染一次set (val) {target[prop] = valrender()},enumerable: true})}// console.log(Object.getOwnPropertyDescriptors(ob))render()function render () {let html = ''for (const prop of Object.keys(ob)) {html += `<p><span>${prop}:</span><span>${ob[prop]}<span/></p>`}div.innerHTML = html}return ob
}
const target = {a: 1, b: 2
}
let obj = observer(target)
obj.a = 3
obj.b = 4

 一开始打印一下 ob,其中是不可枚举,不可被遍历的,所以要在属性配置定义一下该属性

一开始,页面呈现 a 、b值 

重新赋值后,页面也一起变化

两个对象内容相等,也造成内存的浪费 

使用代理实现,不会再浪费一块内存

function observer (target) {const div = document.getElementById('container')const proxy = new Proxy(target, {set (target, prop, value) {Reflect.set(target, prop, value)},get () {return Reflect.get(target, prop, value)}})render()function render () {let html = ''for (const prop of Object.keys(target)) {html += `<p><span>${prop}:</span><span>${target[prop]}<span/></p>`}div.innerHTML = html}return proxy
}
const target = {a: 1, b: 2
}
let obj = observer(target)

 proxy应用——构造函数

1.原本构造函数

class User {constructor(firstName,lastName,age) {this.firstName = firstNamethis.lastName = lastNamethis.age = age}
}

2.使用代理方式偷懒 可以这么写

class User { }
function ConstructorProxy (Class, ...propNames) {// 重写类的底层实现return new Proxy(Class, {construct (target, argumentsList) {const obj = Reflect.construct(target, argumentsList)// 给构造函数对象加上这些属性propNames.forEach((name, i) => {obj[name] = argumentsList[i]})console.log('构造函数被调用了')return obj},})
}
const UserProxy = ConstructorProxy(User,'firstName','lastName','age'
)
// 通过代理告诉 构造函数有三个属性
const obj = new UserProxy('张', '三', 17)
console.log('obj1:', obj)

3.再加一个类也一样

class Monster { }
const monstorProxy = ConstructorProxy(Monster,'attack','defence','hp','rate','name'
)
const obj2 = new monstorProxy(10, 100, 3, 4, 'monster')
console.log('obj2:', obj2)

proxy应用——可验证的函数参数 

function sum (a, b) {return a + b
}
function validatorFunction (func, ...types) {const proxy = new Proxy(func, {apply (target, thisArgument, argumentList) {types.forEach((t, i) => {console.log(t, i)const arg = argumentList[i]console.log(arg)if (typeof arg !== t) {throw new TypeError(`第${i + 1}个参数${argumentList[i]}不满足参数类型`)}})Reflect.apply(target, thisArgument, argumentList)}})return proxy
}
const sumProxy = validatorFunction(sum, "number", "number")
console.log(sumProxy(1, "2"))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/252671.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

React18构建Vite+Electron项目以及打包

一.先创建项目 cnpm create vite 选择React > JavaScript >cd react_vite > cnpm i >npm run dev 二.安装Electron依赖 指定版本相对稳定 cnpm i electron19.0.10 -D cnpm i vite-plugin-electron0.9.3 -D cnpm i electron-builder23.0.1 -D三.创建electron目录…

42、WEB攻防——通用漏洞文件包含LFIRFI伪协议编码算法代码审计

文章目录 文件包含文件包含原理攻击思路文件包含分类 sessionPHP伪协议进行文件包含 文件包含 文件包含原理 文件包含其实就是引用&#xff0c;相当于C语言中的include <stdio.h>。文件包含漏洞常出现于php脚本中&#xff0c;当include($file)中的$file变量用户可控&am…

Leetcode02.05:链表求和

一、题目描述 给定两个用链表表示的整数&#xff0c;每个节点包含一个数位。 这些数位是反向存放的&#xff0c;也就是个位排在链表首部。 编写函数对这两个整数求和&#xff0c;并用链表形式返回结果。 示例&#xff1a; 输入&#xff1a;(7 -> 1 -> 6) (5 -> 9 -…

大学电子学籍档案管理系统建设方案

一、项目背景 随着大学教育规模的扩大和信息化进程的加快&#xff0c;大学电子学籍档案管理系统的建设成为大学管理的重要内容。传统的纸质学籍档案管理方式存在信息难以共享、查询速度慢、存储空间占用大等问题&#xff0c;无法满足大学学籍管理的需求。因此&#xff0c;建设一…

centos安装inpanel

前置条件 安装python yum -y install python 安装 cd /usr/local git clone https://gitee.com/WangZhe168_admin/inpanel.git cd inpanel python install.py 安装过程需要设置账户 密码 端口号 我设置的是admin:admin 10050 使用 打开浏览器,输入 http://192.168.168.…

CentOS7搭建k8s-v1.28.6集群详情

文章目录 1.灌装集群节点操作系统1.1 设置hosts1.2 设置nameserver1.3 关闭防火墙1.4 关闭Selinux1.5 关闭Swap分区1.6 时间同步1.7 调整内核参数1.8 系统内核升级 2.安装Docker2.1 卸载旧Docker2.2 配置Docker软件源2.3 安装Docker 3.部署Kubernets集群3.1 设置 K8s 软件源3.2…

Day 1. 学习linux高级编程之Shell命令和IO

1.C语言基础 现阶段学习安排 2.IO编程 多任务编程&#xff08;进程、线程&#xff09; 网络编程 数据库编程 3.数据结构 linux软件编程 1.linux&#xff1a; 操作系统&#xff1a;linux其实是操作系统的内核 系统调用&#xff1a;linux内核的函数接口 操作流程&#xff…

第二篇:MySQL安装与配置(基于小皮面板(phpstudy))

在第一篇中介绍了数据库的相关概念&#xff0c;了解到SQL是用来操作数据库管理系统的语言&#xff0c;因此要学习数据库技术&#xff0c;数据库管理系统的配备是必不可少的&#xff01; 并且出于流行性与实惠性的双考量而选择MySQL这款数据库管理系统软件 一&#xff0c;工具推…

el-table动态合并

废话就不多说了&#xff0c;直接上代码&#xff01;&#xff01;&#xff01; 合并行 // 方法一 <template><div class"container"><el-table :data"dataSource" :border"true":header-cell-style"{ font-weight: normal,…

《Lua程序设计》-- 学习10

环境&#xff08;Environment&#xff09; 具有动态名称的全局变量 全局变量的声明 由于Lua语言将全局变量存放在一个普通的表中&#xff0c;所以可以通过元表来发现访问不存在全局变量的情况。 正如前面所提到的&#xff0c;我们不允许值为nil的全局变量&#xff0c;因为值为…

LabVIEW风力发电机在线监测

LabVIEW风力发电机在线监测 随着可再生能源的发展&#xff0c;风力发电成为越来越重要的能源形式。设计了一个基于控制器局域网&#xff08;CAN&#xff09;总线和LabVIEW的风力发电机在线监测系统&#xff0c;实现风力发电机的实时监控和故障诊断&#xff0c;以提高风力发电的…

程序员为什么不喜欢关电脑?

目录 标题&#xff1a;程序员为何乐见电脑长时间处于关闭状态&#xff1f; 引言&#xff1a; 一、思维的延续性&#xff1a; 二、环境的连续性&#xff1a; 三、长时间开机的原因&#xff1a; 四、恢复成本的考量&#xff1a; 结论&#xff1a; 特别的&#xff1a; 不是…

DevOps落地笔记-11|持续集成:软件持续集成,发布信手拈来

上一讲我主要介绍了如何快速的构建环境&#xff0c;以及测试阶段对环境的要求。现在测试环境已经不是阻碍软件开发的障碍了&#xff0c;但另一个问题又出现了&#xff1a;每次测试结果不是不理想&#xff0c;就是问题太多无法继续测试。这是因为&#xff0c;团队成员平时都在自…

扫盲软件开发工具低代码

目录 一、低代码是什么&#xff1f; 二、低代码平台的优势和劣势都是什么&#xff1f; 三、低代码操作方式 四、写在最后 一、低代码是什么&#xff1f; 低代码是一套可视化开发工具&#xff0c;它帮开发者把前后端基础功能写扎实&#xff0c;开发者只需要通过填表配置或拖…

Eclipse离线安装maven、jetty、svn插件;附百度网盘资源链接

Eclipse离线安装maven、jetty、svn插件&#xff1b;附百度网盘资源链接 链接&#xff1a;https://pan.baidu.com/s/1zt4-K4AvGZ4EnSqp0vfDGA 提取码&#xff1a;7980

动态扩缩容下的全局流水号设计

关于全局流水号&#xff0c;业内用的比较多的就是雪花算法&#xff0c;一直没理解在动态扩缩容下其中的workId和 datacenterId如何设置&#xff0c;查到了几个方法&#xff1a;reidis中取&#xff0c;待后期实践下。 先简单的介绍一下雪花算法&#xff0c;雪花算法生成的Id由…

代码随想录Day42 | 背包问题理论 416. 分割等和子集

代码随想录Day42 | 背包问题理论 416. 分割等和子集 二维dp解决背包问题一维dp求解背包问题46.携带研究材料二维dp一维dp 416.分割等和子集 二维dp解决背包问题 文档讲解&#xff1a;代码随想录 视频讲解&#xff1a; 带你学透0-1背包问题 状态 利用五部曲来分析二维dp是如何解…

CF1404BTree Tag/ BZOJ0487. 树上追逐详解

1.题目 传送门:Tree Tag - 洛谷 2.思路 我们考虑什么情况下Alice可以获胜. 如果​ ≤ da&#xff0c;则Alice可以一步就追上Bob. 如果Alice处在一个能覆盖整棵树的点&#xff0c;即2da 1≥树的直径&#xff0c;那么Bob也无论走到哪里Alice都能追到,Alice获胜. 其它情况下…

string容器

#include<iostream> using namespace std; //string的构造函数 void test01() {string s1;//默认构造const char *str"holle word";string s2(str);cout<<"s2"<<s2<<endl;string s3(s2);cout<<"s3"<<s3<…

【Vitis】基于C++函数开发组件的步骤

目录 基本步骤 关键领域 • 硬件接口&#xff1a; 任务级并行度&#xff1a; 存储器架构&#xff1a; 微观级别的最优化&#xff1a; 基本步骤 1. 基于 设计原则 建立算法架构。 2. &#xff08;C 语言仿真&#xff09; 利用 C/C 语言测试激励文件验证 C/C 代码的逻辑。…