代理与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.hqwc.cn/news/456327.html

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

相关文章

重新排列链表

不难注意到目标链表即为将原链表分成前后两段然后将后半段反转再依照某种规则链接得到的。这样我们的任务即可划分为三步&#xff1a;找到原链表的中点&#xff0c;将原链表的右半端反转&#xff0c;将原链表的两端合并。可以通过快慢指针找到中点不过要注意链表长度分别为奇偶…

算法学习——LeetCode力扣哈希表篇1

算法学习——LeetCode力扣哈希表篇1 242. 有效的字母异位词 242. 有效的字母异位词 - 力扣&#xff08;LeetCode&#xff09; 描述 给定两个字符串 s 和 t &#xff0c;编写一个函数来判断 t 是否是 s 的字母异位词。 注意&#xff1a;若 s 和 t 中每个字符出现的次数都相同…

Python学习从0到1 day15 Python函数进阶

什么东西的可塑性最强呢&#xff1f; 是水&#xff0c;水能载舟 exciting ——24.2.6 一、函数的多返回值 当一个函数需要多个返回值&#xff0c;该如何书写代码&#xff1f; 按照返回值的顺序&#xff0c;写对应顺序的多个遍历接收即可 变量之间用逗号隔开 支持不同类型的数据…

爬虫(三)

1.JS逆向实战破解X-Bogus值 X-Bogus:以DFS开头&#xff0c;总长28位 答案是X-Bogus,因为会把负载里面所有的值打包生成X-Boogus 1.1 找X-Bogus加密位置&#xff08;请求堆栈&#xff09; 1.1.1 绝招加高级断点&#xff08;日志断点&#xff09; 日志断点看有没有X-B值 日志…

【算法分析与设计】无重复的最长子串

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;算法分析与设计 ⛺️稳中求进&#xff0c;晒太阳 题目 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 示例 1: 输入: s "abcabcbb" 输…

java中String类常用API

前言&#xff1a;在学习java的String类的时候&#xff0c;有很多的API需要了解&#xff0c;下面我将举出其中在新手学习时使用频率较大的几个API。 先大体看一下有哪几个&#xff1a;&#xff08;如图&#xff09; 目录 1.equals&#xff08;&#xff09;和 equalsIgnoreCase&…

maven依赖报错处理(或者maven怎么刷新都下载不了依赖)

maven依赖报错&#xff0c;或者不报错&#xff0c;但是怎么刷新maven都没反应&#xff0c;可以试一下以下操作 当下载jar的时候&#xff0c;如果断网&#xff0c;或者连接超时的时候&#xff0c;会自动在文件夹中创建一个名为*lastupdate的文件&#xff0c;当有了这个文件之后…

【C语言】贪吃蛇 详解

该项目需要的技术要点 C语言函数、枚举、结构体、动态内存管理、预处理指令、链表、Win32API等。 由于篇幅限制 和 使知识模块化&#xff0c; 若想了解 使用到的 Win32API 的知识&#xff1a;请点击跳转&#xff1a;【Win32API】贪吃蛇会使用到的 Win32API 目录 1. 贪吃蛇游…

ISIS 特性验证(ATT置位、渗透、认证)

拓扑图 配置 sysname AR1 # isis 1is-level level-1cost-style widenetwork-entity 49.0001.0000.0000.0001.00 # interface GigabitEthernet0/0/0ip address 12.1.1.1 255.255.255.0 isis enable 1 # interface GigabitEthernet0/0/1ip address 13.1.1.1 255.255.255.0 isis e…

echarts:一个复杂的瀑布图制作

文章目录 成品展示思路介绍1、如何让柱子不是从0开始2、左侧y轴的时间怎么表示3、柱子上的线怎么画出来 做出两个简单柱子下面加上透明柱子合并两个柱子y轴左右各一个坐标轴y轴固定间隔刻度y轴刻度数值转换y轴显示标签添加图例对折线图的点样式进行设置显示点上的数字并对数字做…

【Java基础】关于Java基础的一些有趣的常识!

前言 今天看到了一篇文章&#xff0c;是关于茶余饭后的Java常识的一些有趣解答&#xff0c;我觉得写的很有趣很易懂&#xff0c;所以截取了其中我觉得比较有趣的问题分享给大家。原文&#xff1a;饭后茶余的java常识 - 知乎 (zhihu.com) 1. Java语言的特点有哪些&#xff1f; …

如何利用HubSpot进行个性化营销?

利用HubSpot进行个性化营销可以通过以下步骤实现&#xff1a; 收集客户数据&#xff1a;利用HubSpot的CRM功能&#xff0c;收集客户的基本信息、行为数据和偏好等信息。这些数据可以包括客户的姓名、电子邮件地址、所在行业、购买历史、网站浏览记录等。 建立客户画像&#x…