JavaScript教程(十六) --- 元编程

元编程

Proxy 和 Reflect 对象允许你拦截并自定义基本语言操作(例如属性查找、赋值、枚举和函数调用等)。借助这两个对象,你可以在 JavaScript 进行元级别的编程。

代理

Proxy 对象可以拦截某些操作并实现自定义行为。

例如获取一个对象上的属性:

let handler = {get(target, name) {return name in target ? target[name] : 42;},
};let p = new Proxy({}, handler);
p.a = 1;console.log(p.a, p.b); // 1, 42

Proxy 对象定义了一个 target(这里是一个空对象)和一个实现了 get 陷阱的 handler 对象。这里,代理的对象在获取未定义的属性时不会返回 undefined,而是返回 42

术语

在讨论代理的功能时会用到以下术语:

handler包含陷阱的占位符对象(下译作“处理器”)。

陷阱提供属性访问的方法(这类似于操作系统中陷阱的概念)。

target代理所虚拟化的对象(下译作“目标”)。它通常用作代理的存储后端。JavaScript 会验证与不可扩展性或不可配置属性相关的不变式。

不变式实现自定义操作时保持不变的语义称为不变式。如果你破坏了处理器的不变式,则会引发 TypeError 异常。

处理器和陷阱

以下表格中总结了 Proxy 对象可用的陷阱。详细的解释和例子请看参考页。

处理器 / 陷阱拦截的操作不变式
handler.getPrototypeOf()Object.getPrototypeOf()
Reflect.getPrototypeOf()
__proto__
Object.prototype.isPrototypeOf()
instanceof
  • getPrototypeOf 方法必须返回一个对象或 null
  • 如果 target 不可扩展,Object.getPrototypeOf(proxy) 必须返回和 Object.getPrototypeOf(target) 一样的值。
handler.setPrototypeOf()Object.setPrototypeOf()
Reflect.setPrototypeOf()
如果 target 不可扩展,参数 prototype 必须与 Object.getPrototypeOf(target) 的值相同。
handler.isExtensible()Object.isExtensible()
Reflect.isExtensible()
Object.isExtensible(proxy) 必须返回和 Object.isExtensible(target) 一样的值。
handler.preventExtensions()Object.preventExtensions()
Reflect.preventExtensions()
如果 Object.isExtensible(proxy) 值为 false,那么 Object.preventExtensions(proxy) 只可能返回 true
handler.getOwnPropertyDescriptor()Object.getOwnPropertyDescriptor()
Reflect.getOwnPropertyDescriptor()
  • getOwnPropertyDescriptor 必须返回对象或者 undefined
  • 如果存在一个对应于 target 的属性是不可配置的自有属性,那么该属性不能被报告为不存在的。
  • 如果存在一个对应于 target 的属性是自有属性,且该 target 不可扩展,那么该属性不能被报告为不存在的。
  • 如果并不存在一个对应于 target 的属性是自有属性,且该 target 不可扩展,那么该属性不能被报告为存在的。
  • 如果并不存在一个对应于 target 的属性是自有属性,或存在一个对应于 target 的属性是可配置的自有属性,那么它不能被报告为不可配置的。
  • Object.getOwnPropertyDescriptor(target) 的结果可以通过 Object.defineProperty 应用到 target 上,且不会抛出异常。
handler.defineProperty()Object.defineProperty()
Reflect.defineProperty()
  • 如果 target 不可扩展,那么就不能添加属性。
  • 如果并不存在一个对应于 target 的属性是不可配置的自有属性,那么就不能添加(或修改)该属性为不可配置的。
  • 如果存在一个对应于 target 的属性是可配置的,那么这个属性未必是不可配置的。
  • 如果存在一个对应于 target 的属性,那么 Object.defineProperty(target, prop, descriptor) 将不会抛出异常。
  • 在严格模式下,如果 defineProperty 处理器返回 false,则会抛出 TypeError 异常。
handler.has()

属性查询

foo in proxy

继承属性查询

foo in Object.create(proxy)
Reflect.has()

  • 如果存在一个对应于 target 的属性是不可配置的自有属性,那么该属性不能被报告为不存在的。
  • 如果存在一个对应于 target 的属性是自有属性,且 target 不可扩展,那么该属性不能被报告为不存在的。
handler.get()

属性访问

proxy[foo]
proxy.bar

继承属性访问

Object.create(proxy)[foo]
Reflect.get()

  • 如果对应于 target 的属性是不可写且不可配置的数据属性,那么该属性值必须与其相同。
  • 如果对应于 target 的属性是不可配置的访问器属性,且其 [[Get]] 属性为 undefined,那么该属性值必须为 undefined
handler.set()

属性赋值

proxy[foo] = bar
proxy.foo = bar

继承属性赋值

Object.create(proxy)[foo] = bar
Reflect.set()

  • 如果对应于 target 的属性是不可写且不可配置的数据属性,那么就不能修改该属性的值使其不同于 target 上对应属性的值。
  • 如果对应于 target 的属性是不可配置的访问器属性,且其 [[Set]] 属性为 undefined,那么就不能设置该属性的值。
  • 在严格模式下,如果 set 处理器返回 false,则会抛出 TypeError 异常。
handler.deleteProperty()

属性删除

delete proxy[foo]
delete proxy.foo
Reflect.deleteProperty()

如果存在一个对应于 target 的属性是不可配置的自有属性,那么该属性不能被删除。
handler.ownKeys()Object.getOwnPropertyNames()
Object.getOwnPropertySymbols()
Object.keys()
Reflect.ownKeys()
  • ownKeys 的返回值是一个数组。
  • 返回值中的每个元素类型为 String 或 Symbol。
  • 返回值中必须包含 target 的所有不可配置自有属性的键名。
  • 如果 target 不可扩展,那么返回值中必须有且仅有 target 的所有自有属性的键名。
handler.apply()proxy(..args)
Function.prototype.apply()
Function.prototype.call()
Reflect.apply()
不存在关于 handler.apply 方法的不变式。
handler.construct()new proxy(...args)
Reflect.construct()
返回值必须是一个 Object

可撤销的 Proxy

可以用 Proxy.revocable() 方法来创建可撤销的 Proxy 对象。这意味着可以通过 revoke 函数来撤销并关闭一个代理。

此后,对代理进行的任意的操作都会导致 TypeError。

const revocable = Proxy.revocable({},{get(target, name) {return `[[${name}]]`;},},
);
const proxy = revocable.proxy;
console.log(proxy.foo); // "[[foo]]"revocable.revoke();console.log(proxy.foo); // TypeError: Cannot perform 'get' on a proxy that has been revoked
proxy.foo = 1; // TypeError: Cannot perform 'set' on a proxy that has been revoked
delete proxy.foo; // TypeError: Cannot perform 'deleteProperty' on a proxy that has been revoked
console.log(typeof proxy); // "object", `typeof` 不会触发任何陷阱

反射

Reflect 是一个内置对象,它为可拦截的 JavaScript 操作提供了方法。这些方法与代理处理器所提供的方法类似。

Reflect 并不是一个函数对象。

Reflect 将默认操作从处理器转发到 target

以 Reflect.has() 为例,你可以将 in 运算符作为函数:

JSCopy to Clipboard

Reflect.has(Object, "assign"); // true

更好的 apply 函数

在不借助 Reflect 的情况下,我们通常使用 Function.prototype.apply() 方法调用一个具有给定 this 值和 arguments 数组(或类数组对象)的函数。

Function.prototype.apply.call(Math.floor, undefined, [1.75]);

借助 Reflect.apply,这些操作将变得更加简洁:

Reflect.apply(Math.floor, undefined, [1.75]);
// 1;Reflect.apply(String.fromCharCode, undefined, [104, 101, 108, 108, 111]);
// "hello"Reflect.apply(RegExp.prototype.exec, /ab/, ["confabulation"]).index;
// 4Reflect.apply("".charAt, "ponies", [3]);
// "i"

检查属性定义是否成功

使用 Object.defineProperty,如果成功则返回一个对象,否则抛出一个 TypeError,你可使用 try...catch 块来捕获定义属性时发生的任何错误。因为 Reflect.defineProperty 返回一个布尔值表示的成功状态,你可以在这里使用 if...else 块:

if (Reflect.defineProperty(target, property, attributes)) {// success
} else {// failure
}

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

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

相关文章

大数据建模理论

文章目录 一、数仓概述1、数据仓库概念1.1 概述1.2 数据仓库与数据库的区别1.3 技术选型和架构 2、数仓常见名词2.1 实体2.2 维度2.3 度量2.4 粒度2.5 口径2.6 指标2.7 标签2.8 自然键/持久键/代理键2.9 退化维度2.10 下钻/上卷2.11 数据集市 3、数仓名词之间关系3.1 实体表&am…

java-javafx在普通类里如何弹出javafx的弹窗或者窗口

java-javafx在普通类里如何弹出javafx的弹窗或者窗口 背景代码运行报错解决方法总结参考 背景 想要在一个普通类里弹出一个弹窗 代码 package sample.main;import javafx.application.Application; import javafx.application.Platform; import javafx.embed.swing.JFXPanel…

Spring 事务失效总结

前言 在使用spring过程中事务是被经常用的,如果不小心或者认识不做,事务可能会失效。下面列举几条 业务代码没有被Spring 容器管理 看下面图片类没有Componet 或者Service 注解。 方法不是public的 Transactional 注解只能用户public上&#xff0c…

李沐41_物体检测和数据集——自学笔记

边缘框 1.一个边缘框可以通过4个数字定义(左上xy,右上xy,左下xy,右下xy) 2.标注成本高 目标检测数据集 1.每行表示一个物体(图片文件名、物体类别、边缘框) 2.COCO:80物体、330…

RAG原理详解

什么是RAG 检索增强生成(Retrieval Augmented Generation,简称RAG)为大型语言模型(LLMs)提供了从某些数据源检索到的信息,以此作为生成答案的基础。简而言之,RAG是搜索LLM提示的结合&#xff0…

Mac用户必备神器:Default Folder X,让文件操作更快捷、更智能!

Default Folder X for Mac是一款功能强大的文件管理辅助工具,它为Mac用户带来了前所未有的文件操作体验。🌟 无论是日常办公、学习还是娱乐,Default Folder X都能帮助你更高效地管理文件,让你的工作更加得心应手。💼 …

AD高速板设计(笔记)

Alt左键高亮某个器件或属性,点击任意位置取消高亮。 TP设置旋转角度为45度,即可选中器件按空格旋转时候每次旋转45度。 先画出想要割槽的区域,选中之后TVB即可开槽。 左右翻转电路板:VB DR打开规则设置 UFO对器件进行扇出&#…

Linux系统部署可视化数据多维表格APITable并实现无公网IP远程协同办公

🌈个人主页: Aileen_0v0 🔥热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​💫个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-G5XdKx1vxX0o0PES {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

PHP回显语句详解

PHP中的回显语句是一种常见的输出数据到前端的方法,广泛应用于网页开发中。本文将深入探讨PHP中回显语句的各个方面,包括其基本用法、不同的回显方法、与其他语句的比较、性能考量以及一些高级用法和技巧。 1. 回显语句的基本用法 在PHP中,…

AVM 环视拼接方法介绍

0. 简介 关于车辆的全景环视系统网上已经有很多的资料,然而几乎没有可供参考的代码,这一点对入门的新人来说非常不友好。全景环视系统,又称AVM。在自动驾驶领域,AVM属于自动泊车系统的一部分,是一种实用性极高、可大幅…

面试题总结:HashMap底层原理

不仅仅是一道题,之后的某一天,它可能是破局的关键。 关于HashMap的知识点有哪些呢?分层次展示 1.基础知识: 存储键值对结构、底层数据结构、红黑树和链表 2.位运算与实现 位运算、put、get方法的实现 3.关于锁 segment锁和桶锁、线…

python给图片改名

在Python中,你可以使用os库来遍历一个目录中的所有文件,并使用os.rename()函数来重命名它们。以下是一个简单的示例,该示例会将当前目录下的所有.jpg文件重命名为new_name_1.jpg,new_name_2.jpg,等等。 import os# 获…

Java 中 Set 集合是如何实现添加元素保证不重复的?

Java 中的 Set 集合是一种不允许包含重复元素的集合。它主要通过两种方式来实现确保元素不重复的机制:一是依赖元素的 hashCode() 方法和 equals() 方法,二是底层数据结构的支持。 1. hashCode() 和 equals() 方法 在 Java 中,每个对象都有…

【服务器配置】docker环境配置

docker环境配置 本文是在ubuntu 22.04机器配置docker环境 查看系统的内核版本 uname -a Linux xxf-ThinkStation-P340 5.15.0-101-generic #111-Ubuntu SMP Tue Mar 5 20:16:58 UTC 2024 x86_64 x86_64 x86_64 GNU/Linuxx86 64位 系统 如果是32位 不能安装docker 更新软件…

分布式数据库Polardb-X架构及特点

PolarDB-X架构 计算节点(Compute Node,CN)是系统的入口,采用无状态设计的sql引擎提供分布式路由和计算,包括SQL解析器、优化器、执行器等模块。负责数据分布式路由、计算及动态调度,负责分布式事务2PC协调…

基于java+springboot+vue实现的学生信息管理系统(文末源码+Lw+ppt)23-54

摘 要 人类现已进入21世纪,科技日新月异,经济、信息等方面都取得了长足的进步,特别是信息网络技术的飞速发展,对政治、经济、军事、文化等方面都产生了很大的影响。 利用计算机网络的便利,开发一套基于java的大学生…

文献学习-37-动态场景中任意形状针的单目 3D 位姿估计:一种高效的视觉学习和几何建模方法

On the Monocular 3D Pose Estimation for Arbitrary Shaped Needle in Dynamic Scenes: An Efficient Visual Learning and Geometry Modeling Approach Authors: Bin Li,† , Student Member, IEEE, Bo Lu,† , Member, IEEE, Hongbin Lin, Yaxiang Wang, Fangxun Zhong, Me…

PHP01——php快速入门 之 在Mac上使用phpstudy快速搭建PHP环境

PHP01——php快速入门 之 在Mac上使用phpstudy快速搭建PHP环境 0. 前言1. 下载小皮面板1.1 下载phpstudy(小皮面板)1.2 启动、简单访问1.2.1 启动Apache1.2.2 访问1.2.3 访问自定义文件或页面 2. 创建网站2.1 创建网站2.2 可能遇到的问题2.2.1 hosts权限…

Prompt提示工程上手指南:基础原理及实践-思维树 (ToT)策略下的Prompt

前言 此篇文章已经是本系列的第五篇文章,之前我们已经将检索增强生成(RAG)策略,逐渐我们掌握的知识和技术都在不断提高,对于Prompt的技巧策略也不能只局限于局部运用而要适应LLM大模型的整体框架去进行改进休整。较为主流的LLM模型框架设计基…

提升数据质量的三大要素:清洗prompt、数据溯源、数据增强(含Reviewer2和PeerRead)​

前言 我带队的整个大模型项目团队超过40人了,分六个项目组,每个项目组都是全职带兼职,且都会每周确定任务/目标/计划,然后各项目组各自做任务拆解,有时同组内任务多时 则2-4人一组 方便并行和讨论,每周文档…