js语法---理解反射Reflect对象和代理Proxy对象

Reflect

基本要点

        反射:reflect是一个内置的全局对象,它的作用就是提供了一些对象实例的拦截方法,它的用法和Math对象相似,都只有静态方法和属性,同时reflect也没有构造器,无法通过new运算符构建实例对象(无实例的全局对象);也就是说reflect相当于一个工具类,只对外提供方法进行使用。

tips 拦截方法:拦截方法是指,通过自身方法去覆盖掉原有的默认方法,这样就只会生效拦截方法的操作,而不执行默认操作(例如,setter的作用,覆盖了原有的赋值操作),

这里使用了reflect的方法就不需要再使用默认的方法了

运用示例

以下使用几个简单的reflect的对比示例

Reflect.ownKeys()

获取对象的所有属性(不限于字符串),返回一个数组 ,作用类似Object.keys

Reflect.ownKeys(target)

target:获取自身属性键的目标对象。
let obj ={
  content: 'hello world',
  length: 11,
  char: 'utf-8'
}

let Keys = Object.keys(obj) // 返回一个由属性名组成的数组
console.log(Keys); // ['content', 'length', 'char']

let keys = Reflect.ownKeys(obj) // 返回一个由属性名组成的数组
console.log(keys); // ['content', 'length', 'char']

         这两个方法的效果一致都能拿到对象所有的属性名,但是Object.keys只能得到对象属性的字符串值,如果一个对象的属性包含symbol类型,就无法将其正确的识别出来,而Reflect.ownKeys就可以做到。

关于symbol类型可以参考:js基本类型---symbol标识符_js symbol属于什么类型-CSDN博客

 

Reflect.has()

判定对象中是否存在某个属性,与 in 操作符 相同,返回Boolean值。

let isChar = Reflect.has(obj, 'char') // 判断属性是否存在
console.log(isChar); // true

 Reflect.get()

返回对象(数组)中指定属性的值

Reflect.get(target, propertyKey[, receiver])

// target 需要取值的目标对象

// propertyKey 需要获取的值的键值

// receiver 如果target对象中指定了getter,receiver则为getter调用时的this值。
let content = Reflect.get(obj, 'content') // 获取属性值
console.log(content); // hello world

 

Reflect.set()

静态方法 Reflect.set() 在一个对象上设置一个属性的值,返回Boolean值

Reflect.set(target, propertyKey, value)
Reflect.set(target, propertyKey, value, receiver)

//target 设置属性的目标对象。

//propertyKey 设置的属性的名称。

//value 设置的值。

// receiver 如果遇到 setter,receiver则为setter调用时的this值。
// obj.content = '你好,世界' // 设置属性值

let setContent = Reflect.set(obj, 'content', '你好,世界') // 设置属性值
console.log(setContent); // true,成功时返回true,否则返回false
console.log(Reflect.get(obj, 'content') ); // 你好,世界
console.log(obj.content); // 你好,世界

 

Reflect.deleteProperty()

静态方法 Reflect.deleteProperty() 允许用于删除属性。它很像delete obj.key,但它是一个函数,成功时返回true,否则返回false,这里的成功是根据结果来看的,如果属性不存在,则返回true,否则返回false

Reflect.deleteProperty(target, propertyKey)

// target 删除属性的目标对象。

// propertyKey 需要删除的属性的名称。

 

delete obj.content // 删除属性
console.log(obj); // {length: 11, char: 'utf-8'}

let deleteContent = Reflect.deleteProperty(obj, 'content') // 删除属性
console.log(deleteContent); // true,成功时返回true,否则返回false,这里的成功是根据结果来看的,如果属性存在,则返回true,否则返回false
console.log(obj); // {length: 11, char: 'utf-8'}
console.log(obj);

为什么使用reflect

Reflect 提供的是一整套反射能力 API,它的调用方式,参数和返回值都是统一风格的,在Reflect 出现之前我们只是利用分散的 API 完成一些动态编程的事情,让动态编程有了一个统一的使用标准

和proxy的关系

proxy是代理对象,它的构造器中就包含了和Reflect相同的方法,当使用proxy代理一个引用类型时,就可以简洁的使用Reflect来实现动态编程的效果,

Reflect和proxy的切合度很高,同时也能够避免使用过多分散API带来的隐性错误(如receiver可以解决this的指向问题)和代码的冗余

总之,reflect整合了一套API用于动态化编程,它可以方便简洁的实现proxy的动态拦截代理

tips 动态编程:响应式数据的原理,当修改页面上的某一个值时,页面效果也随之改变

Proxy

Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。

构造器

const p = new Proxy(target, handler)

// target 要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。

// handler 一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为,比如访问和赋值时的而外操作。

Proxy.revocable()

Proxy.revocable() 方法可以用来创建一个可撤销的代理对象。返回一个包含了代理对象本身和它的撤销方法的可撤销 Proxy 对象。

Proxy.revocable(target, handler);
// target 将用 Proxy 封装的目标对象。可以是任何类型的对象,包括原生数组,函数,甚至可以是另外一个代理对象。

// handler 一个对象,其属性是一批可选的函数,这些函数定义了对应的操作被执行时代理的行为。

代理的意义

        首先代理的对象和原对象的属性和值是绑定一致的,可以理解为指向同一个内存地址,也就是说对代理对象的所有操作结果,最终都会回到原对象中,这个过程就可以实现一些其他操作,例如,改变一个对象的值时,将页面重载一遍,引起页面的变化,这个过程就是响应

一个proxy示例


let obj = {
  name: '张三',
  age: 20,
  sex: '男',
  /**
   * @param {any} val
   */
  set address(val){
    this.address = val;
    return val;
  }
}

const p = new Proxy(obj,{
  get: (obj,key,receiver)=>{
    let res = Reflect.get(obj,key,receiver);
    return res;
  },
  set: (obj,key,val,receiver)=>{
    if(typeof val == 'number'){
      console.log('不能设置数字')
      return;
    }
    let res = Reflect.set(obj,key,val,receiver);
    return res;
  }
})
p.name='李四';
p.age=18;
console.log(obj,p)

可以看到 被代理的对象obj会受到p的影响触发改变,而对代理对象属性赋值时,我们可以在中间穿插其他操作,如这里不允许对属性赋值数字,

完整代码和结果展示

reflect.js

let obj ={
  content: 'hello world',
  length: 11,
  char: 'utf-8'
}

let Keys = Object.keys(obj) // 返回一个由属性名组成的数组
console.log(Keys); // ['content', 'length', 'char']

let keys = Reflect.ownKeys(obj) // 返回一个由属性名组成的数组
console.log(keys); // ['content', 'length', 'char']

let isChar = Reflect.has(obj, 'char') // 判断属性是否存在
console.log(isChar); // true

let content = Reflect.get(obj, 'content') // 获取属性值
console.log(content); // hello world
console.log(obj.content); // hello world

// obj.content = '你好,世界' // 设置属性值

let setContent = Reflect.set(obj, 'content', '你好,世界') // 设置属性值
console.log(setContent); // true,成功时返回true,否则返回false
console.log(Reflect.get(obj, 'content') ); // 你好,世界
console.log(obj.content); // 你好,世界

delete obj.content // 删除属性
console.log(obj); // {length: 11, char: 'utf-8'}

let deleteContent = Reflect.deleteProperty(obj, 'content') // 删除属性
console.log(deleteContent); // true,成功时返回true,否则返回false,这里的成功是根据结果来看的,如果属性存在,则返回true,否则返回false
console.log(obj); // {length: 11, char: 'utf-8'}
console.log(obj);

proxy.js 


let obj = {
  name: '张三',
  age: 20,
  sex: '男',
  /**
   * @param {any} val
   */
  set address(val){
    this.address = val;
    return val;
  }
}

const p = new Proxy(obj,{
  get: (obj,key,receiver)=>{
    let res = Reflect.get(obj,key,receiver);
    return res;
  },
  set: (obj,key,val,receiver)=>{
    if(typeof val == 'number'){
      console.log('不能设置数字')
      return;
    }
    let res = Reflect.set(obj,key,val,receiver);
    return res;
  }
})
p.name='李四';
p.age=18;
console.log(obj,p)

更多内容

更多Reflect和proxy相关的方法和属性可以查看:

Reflect - JavaScript | MDN (mozilla.org)

Proxy() 构造函数 - JavaScript | MDN (mozilla.org)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

WiFi/BLE芯片(1):英飞凌

英飞凌AIROC蓝牙芯片的应用场景:

error: ‘LocalParameterization’ is not a member of ‘ceres

一、错误提示: 对于以下报错: error: ‘LocalParameterization’ is not a member of ‘ceres’ error: ‘quatParam’ was not declared in this scope error: expected type-specifier 二、背景: 我是在Ubuntu20.04下,运行…

数据库 | 试卷五试卷六试卷七

1. 主码不相同!相同的话就不能唯一标识非主属性了 2.从关系规范化理论的角度讲,一个只满足 1NF 的关系可能存在的四方面问题 是: 数据冗余度大,插入异常,修改异常,删除异常 3.数据模型的三大要素是什么&…

DDMA信号处理以及数据处理的流程---距离速度测量

Hello,大家好,我是Xiaojie,好久不见,欢迎大家能够和Xiaojie一起学习毫米波雷达知识,Xiaojie准备连载一个系列的文章—DDMA信号处理以及数据处理的流程,本系列文章将从目标生成、信号仿真、测距、测速、cfar检测、测角、目标聚类、目标跟踪这几个模块逐步介绍,这个系列的…

华为---OSPF单区域配置(一)

09、OSPF 9.1 OSPF单区域配置 9.1.1 原理概述 为了弥补距离矢量路由协议的不足,IETF组织开发了一种基于链路状态的内部网关协议——OSPF(Open Shortest Path First,开放式最短路径优先)。 OSPF作为基于链路状态的协议&#xf…

多态性(Java)

本篇学习面向对象语言的第三个特性——多态。 目录 1、多态的概念 2、继承多态实现条件 3、重写 4、重新与重载的区别: 5、向上转移和向下转型 5、1向上转型: 5、2 向下转型 1、多态的概念 多态的概念:通俗来说,就是多种形态…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] LYA 的幸运游戏(100分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 &#x1f…

vivado SLR

描述 超级逻辑区(SLR)是包含在堆叠硅中的单个FPGA芯片 互连(SSI)设备。堆叠式硅互连(SSI)技术使用无源硅 具有微凸块和硅通孔(TSV)的内插器,用于组合多个FPGA管芯 切片&a…

textarea标签改写为富文本框编辑器KindEditor

下载 - KindEditor - 在线HTML编辑器 KindEditor的简单使用-CSDN博客 一、 Maven需要的依赖&#xff1a; 如果依赖无法下载&#xff0c;可以多添加几个私服地址&#xff1a; 在Maven框架中加入镜像私服 <mirrors><!-- mirror| Specifies a repository mirror site to…

Spring源码-xxxAware实现类和BeanPostProcessor接口调用过程

xxxAware实现类作用 以ApplicationContextAware接口为例 ApplicationContextAware的作用是可以方便获取Spring容器ApplicationContext&#xff0c;从而可以获取容器内的Bean package org.springframework.context;import org.springframework.beans.BeansException; import or…

gtk+2.0使用绝对布局实现窗体背景图片的办法

有一个简单的办法实现窗体背景图片,就是使用绝对布局,在窗体中放一个图片控件作为背景,之后所有的控件使用绝对布局在窗体的位置。需要注意之后的控件需要在图片控件之后添加到窗体容器。否则就会被图片覆盖而不能显示。 效果: 代码示例 #include <gtk/gtk.h>int …

云商崆峒乐购618活动2024:企业联动创辉煌

2024年6月18日&#xff0c;云商崆峒乐购618活动在平凉盛大开幕。本次活动由崆峒区商务局、崆峒区电子商务协会与平凉新世纪柳湖春酒业公司联合举办&#xff0c;旨在借助“618”全民线上欢购的热潮&#xff0c;整合平凉本地名优特产&#xff0c;推动崆峒区电商产业及特色网货的发…

进阶篇06——锁

概述 全局锁 表级锁 表锁 元数据锁 元数据锁是系统自动加的&#xff0c;不需要我们手动执行命令添加。 意向锁 意向锁和元数据锁一样&#xff0c;也是在加行锁的时候自动给表加上相应的意向锁&#xff0c;不需要我们手动添加。 行级锁 行锁 读锁和读锁兼容&#xff0c;写锁…

【植物大战僵尸杂交版】致敬传奇游戏玩家——一个普通人的六年坚持

目录 缘起 波澜 凌云 缘起 曾​​​​​​佳伟是《植物大战僵尸》的忠实粉丝&#xff0c;这款游戏给了他很多乐趣&#xff0c;也成为了他度过困难时期的精神支柱。他决定制作杂交版&#xff0c;部分原因是出于对原版游戏的热爱和致敬。 六年前&#xff0c;出于对一些pvz续作…

Java特性之设计模式【访问者模式】

一、访问者模式 概述 在访问者模式&#xff08;Visitor Pattern&#xff09;中&#xff0c;我们使用了一个访问者类&#xff0c;它改变了元素类的执行算法。通过这种方式&#xff0c;元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式&…

4月份最新出品:上海交大动手学大模型教程,快速入门LLM大模型(附课件)

前有 李沐 大神的动手学深度学习 现有 上海交大 的动手学大模型教程&#xff0c;对大模型感兴趣的直接冲&#xff01; 就在4月份上交大发布了动手学大模型教程&#xff0c;这份教程来自上海交大 《人工智能安全技术》 课程讲义拓展&#xff0c;教师是是张倬胜教授。 朋友们…

Windows下MySQL数据库定期备份SQL文件与删除历史备份文件.bat脚本

目录 一、功能需求 二、解决方案 (1)新建文件夹及批处理文件 (2)编写备份脚本 ①完整脚本 ②参数修改 (3)编写定期删除备份脚本 ①根据文件名识别日期进行删除 ② 根据文件的修改日期删除 (4)设置定时器 (5)常见报错与处理 一、功能需求 在Windows系统下…

STM32多功能交通灯系统:从原理到实现

一、功能说明 本交通灯系统采用先进的stm32f103c8t6微处理器为核心控制单元。系统设置东南西北四个方向各配置两位数码管&#xff0c;用以精准展示5至99秒的时间范围&#xff0c;并且允许用户根据实际需求进行灵活调整。 在信号灯配置方面&#xff0c;每个方向均配备左转、直…

【深度学习驱动流体力学】OpenFOAM目录流体力学求解器汇总介绍

下面这些目录结构和其中的求解器和工具展示了OpenFOAM作为一个功能强大且广泛应用的开源CFD软件框架的多样性和灵活性。每个求解器都专门用于解决不同类型的流体动力学问题,从基础的流动模拟到复杂的多相流动和燃烧模拟等各种应用场景。 tree -L 2 . ├── Allclean ├──…
最新文章