代理与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.mzph.cn/news/670470.shtml

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

相关文章

(已解决)vue+element-ui实现个人中心,仿照原神

差一个个人中心页面&#xff0c;看到了这个博主的个人中心&#xff0c;真的很不错 地址&#xff1a;vueelement仿原神实现好看的个人中心 最终效果&#xff1a;

【多模态MLLMs+图像编辑】MGIE:苹果开源基于指令和大语言模型的图片编辑神器(24.02.03开源)

项目主页&#xff1a;https://mllm-ie.github.io/ 论文 :基于指令和多模态大语言模型图片编辑 2309.Guiding Instruction-based Image Editing via Multimodal Large Language Models &#xff08;加州大学圣巴拉分校苹果&#xff09; 代码&#xff1a;https://github.com/appl…

【2024.2.5练习】砍竹子(25分)

题目描述 题目分析 考虑题目是否满足贪心。每次施展魔法会使一段连续的竹子高度变为一半左右的平方根。根据样例&#xff0c;似乎每次让最高的竹子变短就能得到最优解。 假设魔法一次只能对一根竹子使用&#xff0c;永远不出现连续相同高度的竹子&#xff0c;那么显然无论使用…

电商开放API商品采集接口、关键字搜索接口,获取商品ID、商品主图接口

API是application programming interface&#xff08;应用程序接口&#xff09;的简称&#xff0c;是一些预先定义的函数&#xff0c;目的是提供应用程序与开发人员基于某软件或硬件的以访问一组例程的能力&#xff0c;而又无需访问源码&#xff0c;或理解内部工作机制的细节。…

Oracle Vagrant Box 扩展根文件系统

需求 默认的Oracle Database 19c Vagrant Box的磁盘为34GB。 最近在做数据库升级实验&#xff0c;加之导入AWR dump数据&#xff0c;导致空间不够。 因此需要对磁盘进行扩容。 扩容方法1&#xff1a;预先扩容 此方法参考文档Vagrant, how to specify the disk size?。 指…

Linux Shell编程系列--变量的定义与使用

一、目的 上一篇我们简单介绍了shell脚本的组成以及如何运行一个shell脚本&#xff0c;本篇将详解讲解shell中的变量。在Shell脚本中&#xff0c;变量是用来存储和处理数据的基本结构。 二、介绍 1、定义变量 变量名与等号&#xff08;&#xff09;后跟值来定义一个变量&#…

考研数据结构笔记(1)

数据结构&#xff08;1&#xff09; 数据结构在学什么&#xff1f;数据结构的基本概念基本概念三要素逻辑结构集合线性结构树形结构图结构 物理结构&#xff08;存储结构&#xff09;顺序存储链式存储索引存储散列存储重点 数据的运算 算法的基本概念什么是算法算法的五个特性有…

VXLAN:虚拟化网络的强大引擎

1.什么是VXLAN VXLAN&#xff08;Virtual eXtensible Local Area Network&#xff0c;虚拟扩展局域网&#xff09;&#xff0c;是由IETF定义的NVO3&#xff08;Network Virtualization over Layer 3&#xff09;标准技术之一&#xff0c;是对传统VLAN协议的一种扩展。VXLAN的特…

【Spring】Spring事务和事务传播机制

文章目录 什么是事务事务的操作Spring 中事务的实现Spring编程式事务Spring 声明式事务 TransactionalTransactional作用Transactional 详解rollbackFor事务隔离级别Spring 事务隔离级别Spring 事务传播机制 什么是事务 事务&#xff08;Transaction&#xff09;是一个程序中一…

【vue-baidu-map】百度地图组件,实现精准搜索,当前定位功能

实现效果&#xff1a; 代码如下&#xff1a; //引入地图组件 <bmap ref"bmap" map-confirm"confirmPosition" />confirmPosition() {const _this this.$refs.bmapconst center _this.centervar point center.lng , center.latconsole.log(阀控…

JavaEE作业-实验一

目录 1 实验内容 2 思路 3 核心代码 &#xff08;1&#xff09;前端核心代码&#xff1a; &#xff08;2&#xff09;后端核心代码&#xff1a; 4 实验结果 1 实验内容 用Servlet JSP JavaBean实现登录功能 2 思路 ①建好web项目,创建数据库 ②建立两个简单的前端页…

HarmonyOS Next开发----k线图滑动问题

前言 最近做股票软件鸿蒙版本的适配&#xff0c;K线趋势图的手势交互上遇到了问题&#xff0c;这里记录下~ 功能需求&#xff1a; 实现k线趋势图滑动及fling的效果 思路&#xff1a; 1. 借鉴Flutter版本的思路&#xff0c;在K线趋势图上面叠加一个Scroll布局&#xff0c;使…

parted命令进行磁盘分区

1.使用lsblk 查看可用的磁盘 可以看到有sdb sdc两个物理盘还未挂载 2.使用parted命令分区(以sdb为例) 按需要把sdb分成4个逻辑分区 新建磁盘标签类型为gpt 出现提示,输入yes 开始分区: (1)输入mkpart回车,提示输入分区名称,按习惯可命名为sdb1(后面依次sdb2、sdb3)…

部署篇 | MatrixOne与MySQL全面对比

MatrixOne是一款高度兼容MySQL语法的HTAP数据库&#xff0c;在大部分场景下可以直接实现对MySQL的替换。 作为一款开源数据库&#xff0c;MatrixOne 选用对开发者友好的 Apache-2.0 License&#xff0c;支持在主流的 Linux 和 MacOS 系统中直接进行物理部署。在部署方式上&…

JVM 性能调优 - 参数基础(2)

查看 JDK 版本 $ java -version java version "1.8.0_151" Java(TM) SE Runtime Environment (build 1.8.0_151-b12) Java HotSpot(TM) 64-Bit Server VM (build 25.151-b12, mixed mode) 查看 Java 帮助文档 $ java -help 用法: java [-options] class [args...] …

Python中的for循环用法详解,一文搞定它

文章目录 for循环1.for循环的基本语法&#xff08;1&#xff09;遍历不等长多级容器&#xff08;2&#xff09;遍历不等长多级容器&#xff08;3&#xff09;遍历等长的容器 2.变量的解包3.for...else【详细讲解】4.range对象5.总结6.打印 1 ~ 10 跳过57.打印菱形小星星 for循环…

Flink 动态表 (Dynamic Table) 解读

博主历时三年精心创作的《大数据平台架构与原型实现&#xff1a;数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行&#xff0c;点击《重磅推荐&#xff1a;建大数据平台太难了&#xff01;给我发个工程原型吧&#xff01;》了解图书详情&#xff0c;…

docer compose部署simple-docker

简介 一个看似简陋但是功能足够用的docker管理工具 安装 创建目录 mkdir -p /opt/simple-docker cd /opt/simple-docker 创建并启动容器 编写docker-compose.yml文件,内容如下 version: 3 services: redis: image: redis:latest restart: always web: image: registry.cn-…

HR看了都想点开的简历:吸睛模板+撰写技巧

工作致富的第一步&#xff1a;写一份好的简历。一个独特、简单、清晰的个人简历模板可以更好地吸引雇主的注意和兴趣&#xff0c;并帮助你在许多求职者中脱颖而出。如何制作一份令人印象深刻的简历&#xff1f;巧妙地使用个人简历模板是一个不错的选择。在本文中&#xff0c;我…

线性代数:矩阵的初等变换

目录 一、初等行变换 行阶梯 / 行最简 性质 二、矩阵的标准型 三、矩阵的等价 四、初等矩阵 五、重要性质与定理 一、初等行变换 行阶梯 / 行最简 性质 二、矩阵的标准型 三、矩阵的等价 四、初等矩阵 五、重要性质与定理