ES6代理和反射新特性,详细讲解

代理与反射

es6新增了代理和反射特性,这两个特性为开发者提供了拦截并向基本操作嵌入额外行为的能力。

代理基础

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Title</title>
  </head>
  <body>
    <h2>代理与反射</h2>
  </body>
  <script>
    const target = {
      id: 'target'
    }
    const handle = {}
    const proxy = new Proxy(target,handle)
    console.log(proxy.id)
    console.log(target.id)
  </script>
</html>

代理是目标对象的抽象。 所以直接操作代理和直接操作对象,所操作的值都会映射到代理对象上。

代理对象每次执行某个操作(读属性、写属性、定义新属性、查询原型、把它作为函数调用)时,它只会把相应操作发送给处理器对象或目标对象。

Proxy构造器接收两个参数,目标对象处理器对象。如果处理器对象上存在对应方法,代理就调用该方法执行相应操作。如果处理器对象上不存在对应方法,则代理就在目标对象上执行基础操作。

在这里插入图片描述

定义捕获器

使用代理的主要目的是可以定义捕获器。当定义捕获器后,在代理对象上调用基本操作时(比如新增、删除、修改),代理可以在运行这些操作之前调用捕获器,从而拦截并修改相应的行为。

下面看一个例子

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Title</title>
</head>
<body>
  <h2>代理与反射</h2>
</body>
<script>
  const target = {
      id: 'target'
  }
  const handle = {
      get(){
          console.log('捕获器运行')
          return '这是一个捕获器'
      }
  }
  const proxy = new Proxy(target,handle)
  console.log(proxy.id)
  console.log(target.id)
</script>
</html>

在这里插入图片描述

在访问代理对象的属性时,会出发get操作(捕获器函数),但是在原始对象上操作是不会触发的。否则就应该打印两次了。

捕获器函数可以接收三个参数,分别是目标对象,要查询的属性以及代理对象。

那如果我们想在捕获函数内部调用原始对象上的行为呢?Reflect对象为我们提供了这个能力。

下面看一个例子

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Title</title>
</head>
<body>
  <h2>代理与反射</h2>
</body>
<script>
  const target = {
      foo: 'bar'
  }
  const handle = {
      get(){
          return Reflect.get(...arguments)
      }
  }
  const proxy = new Proxy(target,handle)
  console.log(proxy.foo)
  console.log(target.foo)
</script>
</html>

在这里插入图片描述

可以看到值是一样的,那么我们利用这个属性就可以在操作对象时给对象的属性添加一些额外的东西,比如

const target = {
    foo: 'bar'
}
const handle = {
    get(){
        return Reflect.get(...arguments) + '帅'
    }
}
const proxy = new Proxy(target,handle)
console.log(proxy.foo)
console.log(target.foo)

在这里插入图片描述

捕获器的一些限制

在使用捕获器时,需要遵守"捕获器不变式"。原因是因为:如果一个捕获器不遵守捕获器不变式,可能会出现过于反常的行为! 下面来看一个例子:

如果目标对象有一个不可配置且不可写的数据属性,那么在捕获器返回一个与该属性不同的值时,会抛出TypeError

const target = {

}
Object.defineProperty(target,'foo',{
    // 不可配置
    configurable: false,
    // 不可写
    writable: false,
    value: 'bar'
})
const handle = {
    get(){
        return Reflect.get(...arguments) + '帅'
    }
}
const proxy = new Proxy(target,handle)
console.log(proxy.foo)
console.log(target.foo)

在这里插入图片描述

那捕获器函数返回一个一样的值呢?
在这里插入图片描述

实测返回一样的值不会报错。

撤销代理

很简单,调用一个revocable方法。有想要了解具体的可以看看MDN的介绍。

Proxy.revocable() - JavaScript | MDN

看一段代码就知道怎么使用了

const target = {

}
Object.defineProperty(target,'foo',{
    // 不可配置
    // configurable: false,
    // // 不可写
    // writable: false,
    value: 'bar'
})
const handle = {
    get(){
        console.log('运行')
        return Reflect.get(...arguments)
    }
}
const proxy = new Proxy(target,handle)
console.log(proxy.foo)
console.log(target.foo)
const {proxy:proxy1,revoke} = Proxy.revocable(target,handle)
proxy1.foo
revoke()
proxy1.foo

在这里插入图片描述

代理的不足
  1. this指向问题

  2. 代理与内部槽位

    1. 有些js内置类型可能会依赖内部槽位进行一些方法的调用,而代理对象是无法访问到这些方法的,就会导致出错。
const target = new Date()
const proxy = new Proxy(target,{})
console.log(proxy instanceof Date)
proxy.getDate()

输出结果:
在这里插入图片描述

反射

Reflect对象是一个内置的对象,不可以使用new运算符进行实例化,它可以用自己的方法代替原生的操作对象。就是有一个人和你一模一样,你可以不用亲自做一些事情,这个人就帮你做了。

来看一下例子:

const target = {
    foo: 'bar'
}
delete target.foo
console.log(target)

这是我们如果想要删除对象上的某个属性,采取的一种做法。

来看下反射如何做

const target = {
    foo: 'bar'
}
Reflect.deleteProperty(target,'foo')
console.log(target)

在这里插入图片描述

在学习过程中我是有一个疑惑的,为什么JS会出现反射呢? 其实它是为了跟Proxy进行配合。

Proxy可以代理对象的一些操作,比如增加、删除、修改。想一下这个场景:如果Proxy代理了新增操作,然后最后想调用原生的赋值方法,该怎么做?

  1. 自己手动实现一个。
const target = {
    foo: 'bar'
}
let proxy1 = new Proxy(target,{
    get(target, p, receiver) {
        console.log('当前值为::',target[p])
        return target[p]
    }
})
console.log(proxy1.foo)

在这里插入图片描述

  1. 使用反射
const target = {
    foo: 'bar'
}
let proxy1 = new Proxy(target,{
    get(target, p, receiver) {
        console.log('当前值为::',target[p])
        return Reflect.get(target,p,receiver)
    }
})
console.log(proxy1.foo)

在这里插入图片描述

我们无需关心原来操作的实现逻辑,只需要关心我们要为某个操作添加的逻辑即可,原来的逻辑反射会替我们做到。

所以反射的Api是和Proxy捕获器的api一一对应的,当我们想要调用原生操作时,直接使用反射提供的api即可。

总结

从宏观来看,代理是真实JS对象的透明抽象层。在遵循捕获器不变式的前提下,代理可以定义捕获器,可以拦截大部分JS的基本操作和方法。从而增强这些操作。 例如实现装饰器。

反射则封装了一整套与捕获器拦截的操作相对应的方法。可以把反射API看作一套基本操作,包含绝大部分JS对象的API基础。

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

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

相关文章

MYSQL 精通索引【快速理解】

目录 1、什么是索引&#xff1f; 2、索引结构 1.为什么不使用二叉树呢&#xff1f; 2.B树数据结果 3.B树 4.Hash结构 3、索引语法 1.创建索引 2.查看索引 3.删除索引 4、SQL性能分析 1.SQL执行频次 2.慢查询日志 3.profile详情 4.EXPLAIN 5、索引规则 1.最左前缀法则 2.索…

光驱验证 MD5 校验和

步骤 1&#xff1a;在 Ubuntu 上打包文件并生成 MD5 校验和 打包文件 使用 tar 命令将文件夹打包成 tar.gz 文件&#xff1a; tar -czvf my_files.tar.gz /path/to/folder 生成 MD5 校验和 使用 md5sum 命令生成打包文件的 MD5 校验和&#xff1a; md5sum my_files.tar.g…

《网络数据安全管理条例》将于2025年1月1日起正式施行,从业者应如何解读?

2024年9月&#xff0c;国务院总理李强签署国务院令&#xff0c;公布了《网络数据安全管理条例》&#xff08;以下简称《条例》&#xff09;&#xff0c;该条例将于2025年1月1日起正式施行。 这一条例的出台&#xff0c;标志着我国在网络数据安全领域的管理迈上了新的台阶&#…

【MMIN】缺失模态想象网络用于不确定缺失模态的情绪识别

代码地址&#xff1a;https://github.com/AIM3RUC/MMIN abstract&#xff1a; 在以往的研究中&#xff0c;多模态融合已被证明可以提高情绪识别的性能。然而&#xff0c;在实际应用中&#xff0c;我们经常会遇到模态丢失的问题&#xff0c;而哪些模态会丢失是不确定的。这使得…

【Java Web】监听器类型及其使用

文章目录 监听器使用监听器类型ServletContextListenerHttpSessionListenerServletRequestListenerServletContextAttributeListenerHttpSessionAttributeListenerServletRequestAttributeListenerHttpSessionBindingListener 监听器&#xff08;Listener&#xff09;组件用于监…

conda创建 、查看、 激活、删除 python 虚拟环境

1、创建 python 虚拟环境 ,假设该环境命名为 “name”。 conda create -n name python3.11 2、查看 python 虚拟环境。 conda info -e 3、激活使用 python 虚拟环境。 conda activate name 4、删除 python 虚拟环境 conda remove -n name --all ​​ 助力快速掌握数据集…

LaTeX之四:如何兼容中文(上手中文简历和中文论文)、在win/mac上安装新字体。

改成中文版 如果你已经修改了.cls文件和主文档&#xff0c;但编译后的PDF仍然显示英文版本&#xff0c;可能有以下几个原因&#xff1a; 编译器问题&#xff1a;确保你使用的是XeLaTeX或LuaLaTeX进行编译&#xff0c;因为它们对Unicode和中文支持更好。你可以在你的LaTeX编辑器…

视频遥控打药履带机器人技术详解

视频遥控打药履带机器人技术是一种集成了遥控操作、视频监控和履带行走系统的现代化农业植保技术。以下是对该技术的详细解析&#xff1a; 一、技术概述 视频遥控打药履带机器人主要由履带行走系统、药箱、喷雾系统、遥控系统以及视频监控系统等部分组成。通过遥控操作&#…

BB1-NHS ester被用于将各种生物活性分子与蛋白质或其他生物大分子进行共轭连接,2082771-52-4

CAS号&#xff1a;2082771-52-4 中文名&#xff1a;BB1-琥珀酰亚胺酯&#xff0c;BB1-活性酯 英文名&#xff1a;BB1-NHS ester&#xff0c;或BB1-Succinimidyl Ester 分子式&#xff1a;C32H32N6O4 分子量&#xff1a;564.63 纯度&#xff1a;≥95% 供应商&#xff1a;陕…

MongoDB在现代Web开发中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 MongoDB在现代Web开发中的应用 MongoDB在现代Web开发中的应用 MongoDB在现代Web开发中的应用 引言 MongoDB 概述 定义与原理 发展…

激光雷达不够用,怎么办?Ubuntu如何用一个激光雷达实现两个激光雷达的扫描点云效果?点云配准ICP,点云拼接、话题转换、ROS重录制bag包。

1.首先至少得有一个激光雷达&#xff0c;如果没有的话&#xff0c;可以考虑花呗买一个&#xff0c;毕竟研究这东西&#xff0c;有个实物还是比较稳妥&#xff0c;这里我选择的是Livox Mid-360,哈哈哈&#xff0c;公司的&#xff0c;大概长这样&#xff1a; 2. 比如我们想要用激…

STM32H743ZIT6+LWIP+MPU+CUBEMX,通过stm32cubemx完成初始化,ping包亲测没问题,带解释!!

文章耗时两个月&#xff0c;原来写了一半&#xff0c;后来遇到其他项目&#xff0c;中间自己重新画了一块电路板。终于把初始化功能实现了&#xff0c;网上的教程能用的确实凤毛麟角&#xff01; 一、MPU配置详解 个人对stm32H7的MPU属于新接触&#xff0c;为了弄懂&#xff0…

python制作一个简单的端口扫描器,用于检测目标主机上指定端口的开放状态

import argparse # 用于解析命令行参数 from socket import * # 导入 socket 库的所有内容&#xff0c;用于网络通信 from threading import * # 导入 threading 库的所有内容&#xff0c;用于多线程操作 # 创建一个信号量&#xff0c;初始值为 1&#xff0c;用于线程同步&…

网络基础Linux(整理)

计算机网络背景 网络发展 独立模式: 计算机之间相互独立; 网络互联: 多台计算机连接在一起, 完成数据共享; 局域网LAN: 计算机数量更多了, 通过交换机和路由器连接在一起; 广域网WAN: 将远隔千里的计算机都连在一起; 所谓 "局域网" 和 "广域网" 只是一个…

我的第一个PyQt5程序

PyQt5的开发环境配置完成之后&#xff0c;开始编写第一个PyQt5的程序。 方法一&#xff1a;使用将.ui转换成.py文件的方法 import sys from FirstPyQt import Ui_MainWindow from PyQt5.QtWidgets import *#QtCore,QtGui,QtWidgets # from QtTest import Ui_MainWindow#导入Q…

面试:TCP、UDP如何解决丢包问题

文章目录 一、TCP丢包原因、解决办法1.1 TCP为什么会丢包1.2 TCP传输协议如何解决丢包问题1.3 其他丢包情况&#xff08;拓展&#xff09;1.4 补充1.4.1 TCP端口号1.4.2 多个TCP请求的逻辑1.4.3 处理大量TCP连接请求的方法1.4.4 总结 二、UDP丢包2.1 UDP协议2.1.1 UDP简介2.1.2…

Vue全栈开发旅游网项目(11)-用户管理前端接口联调

联调基本步骤 1.阅读接口文档 2.配置接口地址 3.使用axios获取数据 4.将数据设置到模型层 1.发送验证码联调 1.1 配置接口地址 文件地址&#xff1a;src\utils\apis.js //系统相关的接口 const SystemApis {sliderListUrl:apiHost"/system/slider/list/",//发送…

【相关分析方法】MATLAB计算滑动时滞相关系数

【相关分析方法】MATLAB计算滑动时滞相关系数 1 滑动时滞相关系数2 MATLAB代码2.1 函数代码2.2 案例参考滑动时滞相关系数(Moving Time-Lagged Cross-Correlation, TLCC) 是一种常用于分析两个时间序列之间的滞后关系的工具。它可以帮助我们确定一个时间序列相对于另一个时间…

llama-cpp模型轻量化部署与量化

一、定义 定义配置环境遇到的问题&#xff0c;交互模式下模型一直输出&#xff0c;不会停止模型量化Qwen1.5-7B 案例demo 二、实现 定义 主要应用与cpu 上的部署框架。由c完成。配置环境 https://github.com/ggerganov/llama.cpp https://github.com/echonoshy/cgft-llm/blo…

MySQl基础----Linux下数据库的密码和数据库的存储引擎(内附 实操图和手绘图 简单易懂)

绪论​ 涓滴之水可磨损大石&#xff0c;不是由于他力量强大&#xff0c;而是由于昼夜不舍地滴坠。 只有勤奋不懈地努力&#xff0c;才能够获得那些技巧。 ——贝多芬。新开MySQL篇章&#xff0c;本章非常基础&#xff0c;但同时需要一定的Linux基础&#xff0c;所以假若你没学习…