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 & 标准C语言学习 <DAY6>
一.数组 什么是数组:变量的组合,是一种批量定义相同类型变量的方式 定义: 类型名 数组名[数量]; int arr[5]; 注意:数 ...
- 最大流应用(Maximum Flow Application)
1. 二分图匹配(Bipartite Matching) 1.1 匹配(Matching) Def. Given an undirected graph \(G = (V, E)\), subset ...
- 记一次 .NET 某医疗住院系统 崩溃分析
一:背景 1. 讲故事 最近收到了两起程序崩溃的dump,查了下都是经典的 double free 造成的,蛮有意思,这里就抽一篇出来分享一下经验供后面的学习者避坑吧. 二:WinDbg 分析 1. ...
- 这可能是最全面的Spring面试题总结了
Spring是什么? Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架. Spring的优点 通过控制反转和依赖注入实现松耦合. 支持面向切面的编程,并且把应用业务逻辑和系统 ...
- Flutter中如何取消任务
前言 在开发过程中,取消需求是很常见的,但很容易被忽略.然而,取消需求的好处也很大.例如,在页面中会发送很多请求.如果页面被切走并处于不可见状态,就需要取消未完成的请求任务.如果未及时取消,则可能会导 ...
- Android Banner - ViewPager 02
Android Banner - ViewPager 02 现在来给viewpager实现的banenr加上自动轮播 自动轮播的原理,使用handler的延迟消息来实现. 自动轮播实现如下内容 开始轮 ...
- HOOPS Exchange助力Shapr3D产品实现了“无障碍的用户体验”
HOOPS SDK是用于3D工业软件开发的工具包,其中包括4款工具,分别是用于 读取和写入30多种CAD文件格式的HOOPS Exchange.专注于Web端工程图形渲染的HOOPS Communic ...
- openGauss Datakit安装部署
一.问题描述:目前找不到任何关于opengauuss Datakit安装部署的文档,自己来尝试踩坑. DataKit是一个以资源(物理机,数据库)为底座的开发运维工具,将上层的开发运维工具插件化,各插 ...
- sql计算众数及中位数
众数 众数: 情况①:一组数据中,出现次数最多的数就叫这组数据的众数. 举例:1,2,3,3,4的众数是3. 情况② :如果有两个或两个以上个数出现次数都是最多的,那么这几个数都是这组数据的众数. 举 ...
- VUE3企业级项目基础框架搭建流程(2)
typescript安装 这里使用的vue项目语言为:TypeScript,不了解的可以先去学习一下.TypeScript中文网 正常情况下安装typescript的命令为: // 全局安装 npm ...