当前位置: 首页 > news >正文

JavaScript系列——Proxy(代理)

文章目录

    • 概要
    • Proxy 语法
    • handler 对象的方法
    • Proxy 示例
    • 常用handler 对象的方法的参数
      • handler.get()
        • 语法
        • 示例
      • handler.set()
        • 语法
        • 示例
    • 使用场景
      • 验证
      • 值修正及附加属性
    • 小结

概要

Proxy 用于创建一个对象的代理,将对原对象上的操作(属性获取、赋值、函数调用等)转移到这个代理上,拦截对原始对象操作实现自定义操作避免直接操作原对象

也就是说,通过创建一个对象的代理(中间人)后,我们需要先和代理沟通,由代理再对原对象进行沟通,这个过程,允许我们自定义一些操作,实现对原对象的增强。

Proxy 语法

实现一个代理,语法如下:

const p = new Proxy(target, handler)
  • target
    要使用Proxy 包装的目标对象,这个对象可以是任何类型对象、包含原生数组、函数甚至是另一个代理。

  • handler
    一个通常以函数作为属性的对象,其属性中的函数分别定义了在执行各种操作的代理自定义行为。
    开发者就是通过这些属性,告诉代理,需要拦截target 哪些操作,需要做哪些操作。

在Proxy中,JavaScript 允许我们对以下的操作进行拦截,具体有以下handler方法:

handler 对象的方法

  • handler.get()
    属性读取操作的捕捉器。

  • handler.set()
    属性设置操作的捕捉器。

  • handler.has()
    in 操作符的捕捉器。

  • handler.deleteProperty()
    delete 操作符的捕捉器。

  • handler.defineProperty()
    Object.defineProperty 方法的捕捉器。

  • handler.ownKeys()
    Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols 方法的捕捉器。

  • handler.apply()
    函数调用操作的捕捉器。

  • handler.construct()
    new 操作符的捕捉器。

  • handler.getPrototypeOf()
    Object.getPrototypeOf 方法的捕捉器。

  • handler.setPrototypeOf()
    Object.setPrototypeOf 方法的捕捉器。

Proxy 示例

在以下简单的例子中,当对象中不存在属性名时,默认返回值为 37。下面的代码以此展示了 get handler 的使用场景。

const handler = {get: function (obj, prop) {return prop in obj ? obj[prop] : 37;},
};const p = new Proxy({}, handler);
p.a = 1;
p.b = undefined;console.log(p.a, p.b); // 1, undefined
console.log("c" in p, p.c); // false, 37

上面代码中,我们为{} 一个空对象创建了代理p ,给p 为 对象拦截了 属性的获取操作。
并为对象的a 属性赋值了1,给b属性赋值了undefined ,注意,这些操作最后都会由代理转发到源对象身上,也就是说 原始对象{} 的 a\b 属性也有值,和p 一样。

当我们操作p.a 时,代理p 便会拦截 get 方法,执行get函数里面的逻辑。

常用handler 对象的方法的参数

通过上面的简单示例,我们发现,在定义handler 的属性中,我们可以通过方法的参数,获取到一些值,下面对一些常用的方法进行详细讲解

handler.get()

handler.get 方法用于拦截对象的读取属性操作。get 方法可以返回任何值。

该方法会拦截目标对象的以下操作:

  • 访问属性:proxy[foo] 和 proxy.bar
  • 访问原型链上的属性:Object.create(proxy)[foo]
  • Reflect.get()
语法
var p = new Proxy(target, {get: function (target, property, receiver) {},
});
  • target
    目标对象。

  • property
    被获取的属性名。

  • receiver
    Proxy 或者继承 Proxy 的对象

示例
var p = new Proxy({},{get: function (target, prop, receiver) {console.log("called: " + prop);return 10;},},
);console.log(p.a); // "called: a"; ouptut 10

handler.set()

handler.set() 方法是设置属性值操作的捕获器。set() 方法应当返回一个布尔值,true 表示成功,false会抛出异常

该方法会拦截目标对象的以下操作:

  • 指定属性值:proxy[foo] = bar 和 proxy.foo = bar
  • 指定继承者的属性值:Object.create(proxy)[foo] = bar
  • Reflect.set()
语法
new Proxy(target, {set(target, property, value, receiver) {}
});
  • value
    新属性值。

  • receiver
    最初接收赋值的对象。通常是 proxy 本身,但 handler 的 set 方法也有可能在原型链上,或以其他方式被间接地调用(因此不一定是 proxy 本身)

示例
var p = new Proxy({},{set: function (target, prop, value, receiver) {target[prop] = value;console.log("property set: " + prop + " = " + value);return true;},},
);console.log("a" in p); // falsep.a = 10; // "property set: a = 10"
console.log("a" in p); // true
console.log(p.a); // 10

使用场景

验证

通过代理,我们可以对传入的值进行验证,可以借助 handler.set() 方法

我们下面实现以下功能
通过代理,验证一个对象的age 属性,如果设置成非数字或者大于200都会出错,不能成功被赋值,代码如下所示

let validator = {set: function (obj, prop, value) {if (prop === "age") {if (!Number.isInteger(value)) {throw new TypeError("The age is not an integer");}if (value > 200) {throw new RangeError("The age seems invalid");}}// The default behavior to store the valueobj[prop] = value;// 表示成功return true;},
};let person = new Proxy({}, validator);person.age = 100;console.log(person.age);
// 100person.age = "young";
// 抛出异常:Uncaught TypeError: The age is not an integerperson.age = 300;
// 抛出异常:Uncaught RangeError: The age seems invalid

当我们设置age =100 时候,是可以正常执行的。
但我们设置成“young”或者300,都会抛出异常,使得赋值无法执行。

值修正及附加属性

以下products代理会计算传值并根据需要转换为数组。这个代理对象同时支持一个叫做 latestBrowser的附加属性,这个属性可以同时作为 getter 和 setter。

let products = new Proxy({browsers: ["Internet Explorer", "Netscape"],},{get: function (obj, prop) {// 附加一个属性if (prop === "latestBrowser") {return obj.browsers[obj.browsers.length - 1];}// 默认行为是返回属性值return obj[prop];},set: function (obj, prop, value) {// 附加属性if (prop === "latestBrowser") {obj.browsers.push(value);return;}// 如果不是数组,则进行转换if (typeof value === "string") {value = [value];}// 默认行为是保存属性值obj[prop] = value;// 表示成功return true;},},
);console.log(products.browsers); // ['Internet Explorer', 'Netscape']
products.browsers = "Firefox"; // 如果不小心传入了一个字符串
console.log(products.browsers); // ['Firefox'] <- 也没问题,得到的依旧是一个数组products.latestBrowser = "Chrome";
console.log(products.browsers); // ['Firefox', 'Chrome']
console.log(products.latestBrowser); // 'Chrome'

小结

  • proxy用于创建一个对象的代理,实现对原对象操作(属性获取、赋值)进行拦截,从而实现自定义操作,避免直接作用于原对象,通过代理来操作,最后由代理作用于原对象。
  • proxy可以代理任何对象,包括普通对象、函数、甚至是另一个proxy
  • 使用proxy 创建代理时,需要传入原对象和handler
  • handler 是一个对象,有多个方法组成,这些方法名需要以指定形式出现,否则不生效。

相关文章:

JavaScript系列——Proxy(代理)

文章目录 概要Proxy 语法handler 对象的方法Proxy 示例常用handler 对象的方法的参数handler.get()语法示例 handler.set()语法示例 使用场景验证值修正及附加属性 小结 概要 Proxy 用于创建一个对象的代理&#xff0c;将对原对象上的操作&#xff08;属性获取、赋值、函数调用…...

QT第三天

使用QT完成水果计价界面和功能&#xff0c;如下图&#xff1a; 运行结果&#xff1a; 代码&#xff1a; widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QListWidgetItem>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_N…...

Jetpack Compose -> 声明式UI Modifier

前言 本章主要介绍下 Compose 的声明式 UI 以及初级写法&#xff1b; 什么是声明式UI 传统UI 传统 UI 方式来声明UI <androidx.appcompat.widget.LinearLayoutCompat android:layout_width"match_parent" android:layout_height"match_parent&quo…...

windows10 装docker和docker compose

一.windows环境准备 开启过程中的问题&#xff0c;进入bios修复 二.docker下载安装 1.下载 Docker Desktop: The #1 Containerization Tool for Developers | Docker 下载最新版有问题&#xff0c;下载老版本试试 Docker Desktop release notes | Docker Docs 2.安装 三.do…...

第二次面试总结 - 宏汉科技 - Java后端开发

&#x1f9f8;欢迎来到dream_ready的博客&#xff0c;&#x1f4dc;相信您对专栏 “本人真实面经” 很感兴趣o (ˉ▽ˉ&#xff1b;) 专栏 —— 本人真实面经&#xff0c;更多真实面试经验&#xff0c;中大厂面试总结等您挖掘 目录 总结 (非详细) 面试内容(提问内容) - 带答案…...

GPT-4:人工智能的新纪元与未来的无限可能

在人工智能的发展史上&#xff0c;GPT-4的问世标志着一个新的里程碑。作为最新一代的自然语言处理模型&#xff0c;GPT-4不仅在技术上取得了突破&#xff0c;更在应用层面展现了前所未有的潜力。本文将探讨GPT-4的核心技术、应用场景以及它对未来社会的潜在影响。 GPT-4的技术…...

2.右值引用和移动语义

文章目录 右值引用和移动语义&&的特性右值引用优化性能&#xff0c;避免深拷贝移动(move )语义forward 完美转发emplace_back 减少内存拷贝和移动unordered container 无序容器map和unordered_map的差别内部实现机理不同优缺点以及适用处 小结优缺点以及适用处 小结 代…...

深入浅出线程原理

Linux 中的线程本质 线程接口由 Native POSIX Thread Library 提供&#xff0c;即&#xff1a;NPTL 库函数 线程被称为轻量级进程 (Light Weight Process) 每一个线程在内核中都对应一个调度实体&#xff0c;拥有独立的结构体 (task_struct) 内核设计&#xff1a;一个进程对…...

openssl3.2 - 官方demo学习 - saccept.c

文章目录 openssl3.2 - 官方demo学习 - saccept.cEND openssl3.2 - 官方demo学习 - saccept.c 建立TLSServer(使用了证书, 和证书中的私钥), 接收客户端的连接, 并将客户端发来的信息打印到屏幕 笔记 /*! \file saccept.c */ /*! \brief 建立TLSServer(使用了证书, 和证书中…...

JavaScript基础(26)_dom增删改练习

<!DOCTYPE html> <html lang"zh"><head><meta charset"UTF-8"><title>DOM增删改练习</title><link rel"stylesheet" href"../browser_default_style/reset.css"><style>table {borde…...

mac上部署单体hbase

1. 简介 HBase 是一个开源的、分布式的、版本化的典型非关系型数据库。它是 Google BigTable 的开源实现&#xff0c;并且是 Apache 基金会的 Hadoop 项目的一部分1。HBase 在 Hadoop Distributed File System (HDFS) 上运行&#xff0c;作为一个列式存储非关系数据库管理系统…...

【RV1126 学习】SDK/ U-Boot/kernel/rootfs 编译学习

文章目录 RV1126芯片介绍rv1126 模块代码目录相关说明 SDK 包下的脚本使用build.sh 脚本使用envsetup.sh 脚本使用mkfirmware.sh 脚本使用rkflash.sh 脚本使用 U-Boot 编译和配置uboot 的配置修改编译操作 kernel 的修改编译rootfs 编译和配置buildroot 配置busybox 配置 RV112…...

Golang 使用 AST 获取方法和参数名以及应用举例

背景 在做一些自动生成的代码工作时&#xff0c;有时需要知道方法以及对应的参数名 如果仅是方法&#xff0c;利用反射机制就可以解决 而参数名&#xff0c;程序编译后&#xff0c;已经丢失 可以通过 AST 事先获取方法的参数名 有了方法、参数名&#xff0c;加上反射&…...

DC-DC变换集成电路芯片B34063——工作电压范围宽,静态电流小

B34063为一单片DC-DC变换集成电路&#xff0c;内含温度补偿的参考电压源(1.25V)、比较器、能有效限制电流及控制工作周期的振荡器,驱动器及大电流输出开关管等&#xff0c;外配少量元件&#xff0c;就能组成升压、降压及电压反转型DC-DC变换器。 主要特点&#xff1a; ● 工作…...

强力推荐:本地文件加密软件—超详细加密步骤来了!

在数字化时代&#xff0c;数据安全问题日益受到人们的关注。 为了保护个人和企业的重要信息不被泄露&#xff0c;越来越多的人开始使用文件加密软件。 尤其是常常会有数据泄露风险的企业更是需要一款非常给力的加密工具来保护企业数据安全。 一、选择合适的加密软件 在选择加…...

在qml中,ListModel可以与WorkerScript一起使用,从多个线程访问列表模型

在QML中&#xff0c;您可以使用ListModel和WorkerScript一起实现多线程访问列表模型。以下是一个简单的例子&#xff0c;演示了如何在QML中使用这两个元素&#xff1a; import QtQuick 2.15 import QtQuick.Controls 2.15ApplicationWindow {visible: truewidth: 400height: 3…...

rocketmq实现延迟消息

SpringBoot整合RocketMQ发送延时消息 springboot rocketmq 延迟消息 Windows下RocketMQ安装及可视化界面搭建 Java 客户端 RocketMQ延迟消息 项目背景 项目中有延时消息的需求&#xff0c;综合考量RocketMQ比较适合。 RocketMQ支持多维度的延迟级别 支持多种消息类型 基…...

vue倒计时60秒改变按钮状态效果demo(整理)

你可以使用Vue的计时器和绑定状态的方法来实现这个功能。 首先&#xff0c;在data中添加一个计时器countdown&#xff0c;初始值为0。 data() {return {countdown: 0} }<template><div><button click"startCountdown" :disabled"countdown > …...

多区域isis配置实验

一、预习&#xff1a; IS-IS&#xff1a;Intermediate System to Intermediate System&#xff0c;中间系统到中间系统&#xff0c;是ISO为它的CLNP&#xff08;ConnectionLess Network Protocol&#xff09;设计的一种动态路由协议&#xff0c;后来为了提供对IP路由的支持&…...

Ubuntu 22.04.3 LTS arm64 aarch64 ISO jammy-desktop-arm64.iso 下载

Ubuntu 22.04.3 LTS (Jammy Jellyfish) Daily Build 参考 Are there official Ubuntu ARM / aarch64 desktop images? - Ask Ubuntu...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下&#xff0c;越来越多的求职者将目光投向了日本及中日双语岗位。但是&#xff0c;一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧&#xff1f;面对生疏的日语交流环境&#xff0c;即便提前恶补了…...

(十)学生端搭建

本次旨在将之前的已完成的部分功能进行拼装到学生端&#xff0c;同时完善学生端的构建。本次工作主要包括&#xff1a; 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎&#xff08;Physics Engine&#xff09; 物理引擎 是一种通过计算机模拟物理规律&#xff08;如力学、碰撞、重力、流体动力学等&#xff09;的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互&#xff0c;广泛应用于 游戏开发、动画制作、虚…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

基于服务器使用 apt 安装、配置 Nginx

&#x1f9fe; 一、查看可安装的 Nginx 版本 首先&#xff0c;你可以运行以下命令查看可用版本&#xff1a; apt-cache madison nginx-core输出示例&#xff1a; nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

高危文件识别的常用算法:原理、应用与企业场景

高危文件识别的常用算法&#xff1a;原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件&#xff0c;如包含恶意代码、敏感数据或欺诈内容的文档&#xff0c;在企业协同办公环境中&#xff08;如Teams、Google Workspace&#xff09;尤为重要。结合大模型技术&…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全&#xff1a;零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言&#xff1a;云原生安全的范式革命 随着云原生技术的普及&#xff0c;安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测&#xff0c;到2025年&#xff0c;零信任架构将成为超…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案

在大数据时代&#xff0c;海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构&#xff0c;在处理大规模数据抓取任务时展现出强大的能力。然而&#xff0c;随着业务规模的不断扩大和数据抓取需求的日益复杂&#xff0c;传统…...