JavaScript利用反射实现方法注入
1. 引言
反射是一种能够在程序运行时动态访问、修改某个类(对象)中属性和方法的机制
JavaScript在ES6中提供了Reflect 这一个内置的对象,它提供拦截 JavaScript 操作的方法
与之功能类似的有 proxy handler (en-US) 与Object.getOwnPropertyDescriptor()等
以下记述利用反射来实现对JavaScript对象的方法注入,主要使用Reflect和Object.getOwnPropertyDescriptor()来实现
2. Reflect
Reflect并非一个构造函数,所以不能通过 new 运算符对其进行调用,或者将 Reflect 对象作为一个函数来调,Reflect 的所有属性和方法都是静态的(就像 Math 对象),详细文档可参考MDN:Reflect - JavaScript | MDN (mozilla.org)
Reflect的主要功能就是对JavaScript对象进行操作,包括获取属性、修改属性等
在这里,要实现对JavaScript对象的原有方法进行注入,基本思路就是获取对象的原方法,设置一个新方法,在新方法中修改或调用原方法,最后将新方法替换原方法,示例代码如下:
// 定义一个对象
const obj = {
method: function () {
console.log('Original method');
}
};
// 获取对象的属性描述符
const descriptor = Reflect.getOwnPropertyDescriptor(obj, 'method');
// 保存原有方法的引用
const originalMethod = descriptor.value;
// 修改方法的特性
descriptor.value = function () {
// 调用原有方法
Reflect.apply(originalMethod, this, arguments);
console.log('Modified method');
};
// 定义修改后的方法
Reflect.defineProperty(obj, 'method', descriptor);
// 调用方法
obj.method(); // 输出: Original method Modified method
3. Object
Object是JavaScript标准内置对象,其内置多个操作对象方法和属性的静态方法,包括获取属性、修改属性等,更为详细的文档可参考MDN:Object - JavaScript | MDN (mozilla.org)
在这里,要实现对JavaScript对象的原有方法进行注入,基本思路就是和上面是相同的:获取对象的原方法,设置一个新方法,在新方法中修改或调用原方法,最后将新方法替换原方法,示例代码如下:
// 定义一个对象
const obj = {
method: function () {
console.log('Original method');
}
};
// 获取对象的属性描述符
const descriptor = Object.getOwnPropertyDescriptor(obj, 'method');
// 保存原有方法的引用
const originalMethod = descriptor.value;
// 修改方法的特性
descriptor.value = function () {
// 调用原有方法
originalMethod.apply(this, arguments);
console.log('Modified method');
};
// 定义修改后的方法
Object.defineProperty(obj, 'method', descriptor);
// 调用方法
obj.method(); // 输出: Original method Modified method
其实使用Object的静态方法与使用Reflect对象的静态方法差不多,没有太大区别
4. 示例
4.1 添加新方法
JavaScript内置的Date对象没有输出指定格式的方法,可以使用反射进行注入,实现对象的扩展,示例如下:
const getFormattedDate = function (date) {
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
return `${year}-${month}-${day}`;
};
const date = new Date();
Reflect.defineProperty(date, 'getFormattedDate', {
value: getFormattedDate
});
console.log(date.getFormattedDate(date)); // 输出: '2023-7-24'
4.2 扩展原方法
JavaScript内置的Date.prototype.getMonth()方法,返回一个指定的日期对象的月份,为基于 0 的值(0 表示一年中的第一月)
const date = new Date();
console.log(date.getMonth()); // 输出: 6
现在修改为基于 1 的值(1 表示一年中的第一月)
const date = new Date();
const originalMethod = Reflect.get(date, 'getMonth');
Reflect.defineProperty(date, 'getMonth', {
value: function () {
return originalMethod.apply(this, arguments) + 1;
}
});
console.log(date.getMonth()); // 输出: 7
5. 参考资料
[1] Reflect - JavaScript | MDN (mozilla.org)
[2] Object - JavaScript | MDN (mozilla.org)
[3] Date - JavaScript | MDN (mozilla.org)
JavaScript利用反射实现方法注入的更多相关文章
- 利用反射调用方法时,处理ref,out参数需要注意的问题(转)
转自:http://www.68idc.cn/help/buildlang/ask/20150318283817.html 项目中如下的泛型方法,因为要在运行时,动态指定类型参数,所以要利用反射来实现 ...
- laravel中如何利用反射实现依赖注入
依赖注入 在一个类中经常会依赖于其他的对象,先看一下经典的写法 class Foo { public $bar; public function __construct() { $this->b ...
- asp.net一般处理程序利用反射定位方法
asp.net的一般处理程序我想大家用得都不少,经常会如下如下的代码: using System; using System.Collections.Generic; using System.Lin ...
- javascript利用拷贝的方法实现导出excel(可以导出表格线)
Js代码: <script language=javascript> function preview() { window.clipboardData.setData("Tex ...
- java工具类-接受请求参数,并利用反射调用方法
public String a(HttpServletRequest request,HttpServletResponse response) throws JSONException, IOExc ...
- Python基础篇【第3篇】: Python异常处理、反射、动态导入、利用反射的web框架
异常处理 什么是异常? 异常即是一个事件,该事件会在程序执行过程中发生,影响了程序的正常执行. 一般情况下,在Python无法正常处理程序时就会发生一个异常.异常是Python对象,表示一个错误.当P ...
- 反射main方法
利用Java反射机制去调用其他类的main方法基于这种情形: 当程序中的某个类在运行到某处需要去调用其他类的main方法时,如果此程序并不知道此main方法所属类的名称,而只是在程序中接受某一代表此m ...
- C#利用反射调用PB编译的COM组件
问题: 1.根据COM组件的ProgID,得到COM组件公开的类型 2.创建COM组件提供的类型的对象 3.调用执行方法 正确姿势 C#利用反射调用(后期绑定)PB编译的COM组件 C#调用COM组件 ...
- <五>JDBC_利用反射及JDBC元数据编写通用的查询方法
此类针对javaBean类写了一个通用的查询方法,List<javaBean> 通用查询更新中...:通过学习,深刻体会到学会反射就等于掌握了java基础的半壁江山! 一.使用JDBC驱动 ...
- 利用反射及JDBC元数据编写通用查询方法
元数据:描述数据的数据,ResultSetMetaData是描述ResultSet的元数据对象,从它可以得到数据集有多少了,每一列的列名... ResultSetMetaData可以通过ResultS ...
随机推荐
- NC207751 牛牛的旅游纪念品
题目链接 题目 题目描述 牛牛在牛市的旅游纪念商店里面挑花了眼,于是简单粗暴的牛牛决定--买最受欢迎的就好了. 但是牛牛的背包有限,他只能在商店的n个物品里面带m个回去,不然就装不下了. 并且牛牛希望 ...
- phpBB3在Nginx反向代理中的X-Forwarded-For IP检查
记录一下phpBB3对反向代理中的IP处理机制 处理几个phpBB3项目迁移, 部分运行场景转移到内网, 需要外网通过nginx/openresty之类的网关反向代理进行访问. 在网关处已经正确配置了 ...
- STC系列8位MCU在Windows下的开发
STC系列 MCS-51 8位MCU 简介 STC的8位MCU有89/90/10/11/12/15/8(A/F/G/H)这几个大系列, 都是8051衍生的8位单片机, 每个系列的特点如下 STC89系 ...
- 前端树形Tree数据结构使用-🤸🏻♂️各种姿势总结
01.树形结构数据 前端开发中会经常用到树形结构数据,如多级菜单.商品的多级分类等.数据库的设计和存储都是扁平结构,就会用到各种Tree树结构的转换操作,本文就尝试全面总结一下. 如下示例数据,关键字 ...
- Redis客户端汇总
编程客户端 已经支持了许多编程语言,详见:https://redis.io/docs/clients/ 图形客户端 1.Another Redis Desktop Manager 支持哨兵, 集群, ...
- 常见的问题系列--- Swagger @ApiOperationSupport忽略失效的问题
https://www.cnblogs.com/hujunwei/p/15853307.html
- FFmpeg开发笔记(七):ffmpeg解码音频保存为PCM并使用软件播放
若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...
- 案例分享:Qt高频fpga采集数据压力位移速度加速度分析系统(通道配置、电压转换、采样频率、通道补偿、定时采集、距离采集,导出exce、自动XY轴、隐藏XY轴、隐藏显示通道,文件回放等等)
需求 1.0-7通道压力采集,采集频率1~100Khz(1,10,20,30-1000Khz): 2.0-7通道压力,可设置补偿值,测量范围: 3.编码器0,1脉冲采集,计算位移,速度,加速度 ...
- django学习第七天---创建多表结构,创建第三张表的三种方式,创建模型类时的一些元信息配置,多表增加
图书管理系统作业知识点整理 知识点1: print(request.POST.dict())#dict()方法能将QueryDict类型数据转换为普通字典类型数据 传数据时,可以用**{}打散的方式来 ...
- 【Azure 存储服务】使用PowerShell脚本创建存储账号(Storage Account)的共享访问签名(SASToken) : New-AzStorageContainerSASToken
问题描述 使用PowerShell脚本如何来创建存储账号(Storage Account)的共享访问签名呢?查询到可以使用 New-AzStorageContainerSASToken 命令来生成Az ...