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

news2024/11/16 17:41:59

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.coloradmin.cn/o/1839472.html

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

相关文章

vue自建h5应用,接入企业微信JDK(WECOM-JSSDK),实现跳转添加好友功能

一、项目场景: 1、使用vue开发了一套h5页面的项目 2、这个h5链接是在企业微信里某个地方打开的 3、打开页面的时候有一个好友列表,点击好友列表某一条复制手机号跳转到企业微信添加好友页面 二、实现的效果图 博客只允许上传gif图,所以我只…

SQL注入-下篇

HTTP注入 一、Referer注入 概述 当你访问一个网站的时候,你的浏览器需要告诉服务器你是从哪个地方访问服务器的。如直接在浏览器器的URL栏输入网址访问网站是没有referer的,需要在一个打开的网站中,点击链接跳转到另一个页面。 Less-19 判…

预算有限?如何挑选经济适用的ERP系统?

中小企业在运营过程中,经常面临着一个共同的挑战——如何在有限的预算内挑选到一款既符合业务需求又经济适用的ERP系统。然而,市场上ERP系统种类繁多,价格差异大,功能复杂,使得许多企业在选择时感到迷茫和困惑。 如果…

【BEV】BEVFormer总结

本文分享BEV感知方案中,具有代表性的方法:BEVFormer。 它基于Deformable Attention,实现了一种融合多视角相机空间特征和时序特征的端到端框架,适用于多种自动驾驶感知任务。 主要由3个关键模块组成: BEV Queries Q&am…

带你了解甘肃独特的调料-苦豆粉

在众多的调味料中,苦豆粉是一种相对小众但却极具特色的存在。今天,就让我们一起深入探究甘肃特产苦豆粉的奇妙世界。苦豆粉,又被称为胡巴豆、大巴豆等,它主要源自于一种豆科植物。很多人初次接触苦豆粉时,可能会被它独…

13.2 Go 接口的动态性

💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

RK3588 Android12音频驱动分析全网最全

最近没有搞音频相关的了,在搞BMS, 把之前的经验总结一下。 一、先看一下Android 12音频总架构 从这张图可以看到音频数据流一共经过了3个用户空间层的进程,然后才流到kernel驱动层。Android版本越高,通用性越高,耦合性越低&#…

【Portswigger 学院】CORS

教程和靶场来源于 Burpsuite 的官网 Portswigger:Cross-origin resource sharing (CORS) - PortSwigger 跨域资源共享(Cross-origin resource sharing,CORS)是一种浏览器机制,允许浏览器访问不同源的资源。同源策略的作…

【Python】已解决Python错误:ImportError: cannot import name get_column_letter的报错解决办法

【Python】已解决Python错误:ImportError: cannot import name get_column_letter的报错解决办法 😎 作者介绍:我是程序员洲洲,一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家…

Chat-TTS chat-tts-ui 实机部署上手测试!Ubuntu服务器实机 2070Super*2 8GB部署全流程

项目介绍 开源的项目,感谢各位大佬的贡献! 官方介绍:一个简单的本地网页界面,使用ChatTTS将文字合成为语音,同时支持对外提供API接口。A simple native web interface that uses ChatTTS to synthesize text into spe…

没有名为 keras.preprocessing 的模块

估计是因为版本原因 我安装的是 3.3.3版本 >>> import keras >>> print(keras.__version__) 3.3.3 keras.preprocessing.image 将 keras.preprocessing.image 改为 from keras_preprocessing.image 之后报image_type啥的错误,后面查找之后…

C++ 84 之 文件读写

#include <iostream> #include <cstring> #include <string> using namespace std; #include <fstream> // 文件流的头文件int main() {// 写入: 文件内容// (文件位置&#xff0c; 如果这个不存在&#xff0c; 就新建一个)// 写法1&#xff1a; of…

JAVA实现利用phantomjs对URL页面(网页)进行转图片保存

一、前期准备 1、下载phantomjs工具 地址&#xff1a;https://phantomjs.org/download.html 解压到指定文件夹&#xff0c;后续代码要调用该工具&#xff0c;记住路径 2、准备好模板NetToPicMoban.js 用于给phantomjs提供需要执行的js&#xff0c;具体放在那看自己的需求&…

运算放大器(运放)缓冲器(跟随器)电路

运算放大器(Operational Amplifier) 运算放大器(Operational Amplifier)是一种差分放大器&#xff0c;具有高输入电阻、低输出电阻、高开放增益&#xff08;开环增益&#xff09;&#xff0c;并具有可放大输入引脚与-输入引脚间的电压差的功能。 设计目标 输入输入输出输出频…

“Photoshop AI插件:StartAI的全面使用攻略

随着人工智能技术的飞速发展&#xff0c;Photoshop作为设计师们不可或缺的工具&#xff0c;也在不断地融入AI技术&#xff0c;以提升设计效率和效果。在2024年&#xff0c;PSAI插件StartAI因其强大的功能和易用性&#xff0c;成为了Photoshop用户的得力帮手。下面来给大家详细介…

银行数仓项目实战(五)--搭建数仓和数据标准化

文章目录 搭建数仓数据采集 标准层 搭建数仓 数据采集 业务系统源 -》ODS贴源层&#xff0c;添加标签&#xff0c;添加系统来源&#xff0c;添加时间戳 问甲方要建表语句&#xff0c;自己添加etldt字段和来源字段&#xff0c;通过之前文章教的Kettle把数据抽到自己数据库中。…

远程桌面另一台服务器连接不上,局域网IP如何访问另一台服务器

在IT运维工作中&#xff0c;远程桌面连接是日常工作中不可或缺的一部分。然而&#xff0c;当尝试远程桌面连接至另一台服务器时&#xff0c;如果连接不上&#xff0c;可能会引发一系列问题&#xff0c;影响到工作效率和信息安全。特别是在局域网环境中&#xff0c;确保能够正确…

MySQL学习——创建MySQL Workbench中的Connections

在MySQL Workbench中&#xff0c;Connections&#xff08;连接&#xff09;是用户与MySQL数据库进行交互的桥梁。 本文将添加一个新连接&#xff0c;该连接可以是初始连接&#xff0c;也可以是附加连接。在开始之前&#xff0c;必须安装、启动MySQL服务器的实例&#xff0c;并…

今年618各云厂商的香港服务器优惠活动汇总

又到了一年618年中钜惠活动时间&#xff0c;2024年各大云服务器厂商都有哪些活动呢&#xff1f;有哪些活动包括香港服务器呢&#xff1f;带着这些问题&#xff0c;小编给大家一一讲解各大知名厂商的618活动有哪些值得关注的地方&#xff0c;如果对你有帮助&#xff0c;欢迎点赞…

SK投屏助手:电脑控制手机,游戏与App轻松畅玩

SK投屏助手让您将手机画面完美投射至电脑屏幕&#xff0c;而且不止于此&#xff01;现在&#xff0c;您可以利用电脑反向控制手机&#xff0c;轻松操作各种游戏和应用程序。无论是在家中放松还是在工作中提高效率&#xff0c;SK投屏助手都能成为您的得力助手。立即体验无缝连接…