js代理(Proxy) 和 反射(Reflection)
在实际开发中经常会遇到js抛出的错误,但是我们有没有想过自己去接管js异常验证,根据自己的需求抛出异常呢?原本也许不行,但是在es6出来后就可以做到了
一、代理(Proxy)
什么是‘代理’ 呢?代理:就是调用new 创建一个和目标(traget)对象一直的虚拟化对象,然该代理中就可以拦截JavaScript引擎内部目标的底层对象的操作;这些底层操作被拦截后会触发响应特定操作的陷阱函数
来看个简单的案例
let tartget = {};
let proxy = new Proxy(target,{});
proxy.name = 'proxy';
console.log(proxy.name); // proxy
console.log(tartget .name); // proxy
tartget .name = 'tartget';
console.log(proxy.name); // target
console.log(tartget .name); // target
如案例
如proxy.name = 'proxy'; 将proxy赋值给proxy.name时,代理就会将该操作转发给目标,执行name属性的创建;然而他只是做转发而不会存储该属性;
so他们之间存在一个相互引用;tartget .name设置一个新值后,proxy.name值也改变了;
二、反射(Reflect)
那反射又是什么呢?反射:它提供了一个Reflect对象API;该对像中的方法默认特性与底层的操作对应;而每一个代理陷阱会对应一个命名和参数都相同的Reflect方法(其实就是每个代理陷阱都会对应一个Reflect api接口供覆写JavaScript底层操作)
映射关系如下表:
| 代理陷阱 | 覆写的特性 | 默认特性 |
|---|---|---|
| get | 读写一个属性值 | Reflect.get() |
| set | 写入一个属性 | Reflect.set() |
| has | in操作 | Reflect.has() |
| deleteProperty | delete操作符 | Reflect.deleteProperty() |
| getAPrototypeof | Object.getAPrototypeof () | Reflect.getAPrototypeof () |
| setAPrototypeof | Object.setAPrototypeof () | Reflect.setAPrototypeof () |
| isExtensible | Object.isExtensible() | Reflect.isExtensible() |
| preventExtensions | Object.preventExtensions() | Reflect.preventExtensions() |
| getOwnPropertyDescriptor | Object.getOwnPropertyDescriptor() | Reflect.getOwnPropertyDescriptor() |
| defineaProperty | Object.defineaProperty() | Reflect.defineaProperty() |
| ownKeys | Object.keys() 、 Object.getOwnPropertyNames()和 Object.getOwnPropertySysmbols() | Reflect.ownKeys() |
| apply | 调用一个函数 | Reflect.apply() |
| construct | 用new调用一个函数 | Reflect.construct() |
三、使用set陷阱验证属性
接下来使用set陷阱来验证一下对象属性赋值操作(如为对象新增属性,要求必须赋值为int)
let target = {
name :'target'
};
let proxy = new Proxy(target,{
set(trapTarget,key,value,receiver){
//忽略不希望受到影响的已有属性
if(!trapTarget.hasOwnProperty(key)){
if(isNaN(value)){
throw new TypeError("属性必须是数字哟,亲!");
}
}
// 添加属性
return Reflect.set(trapTarget,key,value,receiver);
}
});
// 添加一个新属性
proxy.count = 1;
console.log(proxy.count); // 1
console.log(proxy.count); // 1
// 由于目标已有name属性,so 如上第一个if不成立(赋值成功)
proxy.name= "proxy";
console.log(proxy.name); // proxy
console.log(proxy.name); // proxy
// 新建一个属性同时赋值一个非int 值,第一个if成立,第二个if验证isNaN(key) = true 即抛出异常
proxy.anotherName = "proxy";
案例中set(trapTarget,key,value,receiver) 这个set陷阱默认接收 四个参数
- trapTarget 用于接收属性(代理的目标)的对象
- key 要写入的属性键(字符串或Symbol类型)
- value 被写入的属性的值
- receiver 操作发生的对象(通常是代理)
四、使用get 陷阱验证对象结构
如
let target = {};
console.log(target.name); // undefined
在JavaScript中调用一个对象不存在的属性不会报错,反而使用undefined代替被读取属性的值
而喝多时候会带来意想不到的bug,现在我们可以使用get陷阱来验证该问题
依然看这个案例
let proxy = new Proxy(target,{
get(trapTarget,key,receiver){
//忽略不希望受到影响的已有属性
if(!(key in receiver)){
throw new TypeError("sorry 亲! 你找的 "+key+" 属性不存在。!")
}
// 添加属性
return Reflect.get(trapTarget,key,receiver);
}
});
// 添加一个属性,
proxy.name= "proxy";
console.log(proxy.name); // proxy
// 读取一个不存在的属性 直接会抛出异常
console.log(proxy.nme);
如上使用in操作判断receiver中是否存在被读取的属性;如果没有抛出异常
其中get(trapTarget,key,receiver) 参数
- trapTarget 被读取属性源对象(代理的目标)
- key 要读取的属性键(字符串或Symbol类型)
- receiver 操作发生的对象(通常是代理)
五、函数代理apply和construct陷阱
使用这个两个陷阱来验证函数调用时的参数的正确性
如下案例
// 参数求和
function sum (...values){
return values.reduce((previous,current) => prvious + current, 0);
} let sumProxy = new Proxy(sum,{
apply:function(trapTarget,thisArg,argumentList){
argumentList.forEach(arg => {
if(typeof arg !== "number"){
throw new TypeError("所有参数必须是数字,亲!");
}
});
return Reflect.apply(trapTarget,thisArg,argumentList);
},
// 防止使用new 关键字调用
construct:function(trapTarget,argumentList){
throw new TypeError("亲,你不能这么干,该函数不能通过new调用。");
}
}); // 测试哈
console.log(sumProxy(1,2,3,4)); // 10 // 传入一个非数字的属性值试试 【直接抛出异常】
console.log(sumProxy(1,“2”,3,4)); // 10 // 同样使用new调用 【直接抛出异常】
let result = new sumProxy();
apply陷阱和Reflect.apply()都接受同样的参数
- trapTarget 被执行的函数(代理的目标)
- thisArg 函数被调用时内部的this的值
- argumentList传递给函数的参数数组
当使用new调用函数时 会触发construct陷阱,接收的参数为
- trapTarget 被执行的函数(代理的目标)
- argumentList传递给函数的参数数组
其中Reflect.construct()第三个参数是newTarget 这是一个可选参数。用于指定该函数内部
new.target的值
看到这里有没有感觉这个对于js项目代码检测还是蛮有用处的呢。
ok先到这里,时间不早了改且休息了;改天继续…
js代理(Proxy) 和 反射(Reflection)的更多相关文章
- 代理(Proxy)和反射(Reflection)
前面的话 ES5和ES6致力于为开发者提供JS已有却不可调用的功能.例如在ES5出现以前,JS环境中的对象包含许多不可枚举和不可写的属性,但开发者不能定义自己的不可枚举或不可写属性,于是ES5引入了O ...
- JAVA设计模式-动态代理(Proxy)源码分析
在文章:JAVA设计模式-动态代理(Proxy)示例及说明中,为动态代理设计模式举了一个小小的例子,那么这篇文章就来分析一下源码的实现. 一,Proxy.newProxyInstance方法 @Cal ...
- [整理]C#反射(Reflection)详解
本人理解: 装配件:Assembly(程序集) 晚绑定:后期绑定 MSDN:反射(C# 编程指南) -----------------原文如下-------- 1. 什么是反射2. 命名空间与装配件的 ...
- 【设计模式】学习笔记17:代理模式之保护代理与Java反射
本文出自 http://blog.csdn.net/shuangde800 本笔记内容: 1. Java动态代理,反射机制 2. 保护代理 3. 应用保护代理实现的约会系统 ----------- ...
- Webpack代理proxy配置,解决本地跨域调试问题,同时允许绑定host域名调试
Webpack代理proxy配置,解决本地跨域调试问题,同时允许绑定host域名调试 会撸码的小马 关注 2018.05.29 17:30* 字数 212 阅读 1488评论 0喜欢 2 接到上一章, ...
- 浅谈Java代理一:JDK动态代理-Proxy.newProxyInstance
浅谈Java代理一:JDK动态代理-Proxy.newProxyInstance java.lang.reflect.Proxy:该类用于动态生成代理类,只需传入目标接口.目标接口的类加载器以及Inv ...
- AGS API for JS代理页的使用
AGS API for JS代理页的使用 1.概述 代理页即使用后端语言编写的请求转发页面,部署在Web应用端.客户端请求先发送到该代理页,代理页再将该请求转发到服务器处理,服务器处理结果再经代理页转 ...
- C#反射(Reflection)详解
1. 什么是反射2. 命名空间与装配件的关系3. 运行期得到类型信息有什么用4. 如何使用反射获取类型5. 如何根据类型来动态创建对象6. 如何获取方法以及动态调用方法7. 动态创建委托 1.什么是反 ...
- JAVA设计模式-动态代理(Proxy)示例及说明
在Mybatis源码解析,一步一步从浅入深(五):mapper节点的解析文章的最后部分,我们提到了动态代理的概念,下面我们就简单了解一下动态代理. 一,概念 代理设计模式的目的就是在不直接操作对象的前 ...
- ArcGIS JS 使用Proxy之 Printing Tools unable to connect to mapServer
ArcGIS JS使用Proxy.ashx将地图服务隐藏,并在微博服务器端增加了地图服务权限判断. Proxy.ashx做了如下设置, <serverUrl url="http://l ...
随机推荐
- Linux文件上传下载--rz/sz命令
原文地址:https://www.cnblogs.com/igoodful/p/14694038.html 1.rz 命令 1.1 命令简介 rz 命令(Receive ZMODEM),使用 ZMOD ...
- java选择结构-switch
java选择结构-switch java的另一个多选择结构switch-case case中的value为常数值. 不加break,会一直执行到最后,包括default(case穿透) switch( ...
- Redis 故障排查
系统性学习,移步IT-BLOG 要进行 Redis 的故障定位,一般通过分析 Redis 日志.应用日志和 Redis 的监控信息来定位相关问题. 一.Redis 日志设置 [1]日志文件:Redis ...
- 你需要知道的Symbols
著名symbol 著名symbol是一个在不同领域中都相同且未注册的symbol.如果我们要列出著名symbol,它们会是: Symbol.iterator Symbol.toStringTag Sy ...
- Nmap基本使用【速查版】
列举远程机器开放的端口 nmap [域名] 列举远程机器开放的端口和服务 nmap --dns-servers 8.8.8.8 [域名] nmap进行探测之前要把域名通过DNS服务器解析为IP地址,我 ...
- 逍遥自在学C语言 | 变量、常量与数据类型
前言 一.人物简介 第一位闪亮登场,有请今后会一直教我们C语言的老师 -- 自在. 第二位上场的是和我们一起学习的小白程序猿 -- 逍遥. 二.基本数据类型 1.整型 C语言中的整型数据如下表所示: ...
- 最新centos7 部署 k8s v1.26,简单易懂,跟着命令敲就完事
其实没什么好说的,搭环境搞了一整天,人已经麻了,踩了很多坑,网上教程的版本大都比较旧,总是和最新版本各种地方不兼容,把坑踩完了,k8s目前最新的版本是v1.26,跟着命令敲就行了,我已经重复部署了很多 ...
- ARM 详解
一.ARM 的发展史 ARM 的发展历史可以追溯到 1978 年,当年克里斯·库里(Chris Currry)所任职的公司遭遇财务危机,发展每况愈下,库里在和创始人深入沟通后,决定离职.当时的库里对微 ...
- [Chrome]插件的导出与导入[转载]
1 文由 毕竟是在墙内,暂时又没有有效的FQ工具,换设备了,但需要使用原先旧设备下载的插件.只能出此下策liao~ 2 导出插件 step1 Chrome: 进入插件管理界面 Chrome: 更多工具 ...
- 写一个 Hello SpringBoot2 项目
需求:向浏览发送/hello请求,并响应 Hello,Spring Boot 2 解决: 项目目录:controller层.Main启动项.pom.xml controller层:写好逻辑跳转,当浏览 ...