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 ...
随机推荐
- springboot--配置格式文件
修改端口号的三种方法 1.server.port = 80 2.新建application.yml文件. 3.新建application.yaml文件. 配置文件加载顺序: 当三个文件都存在时prop ...
- cost function 成本函数
cost function 成本函数 cost function-成本函数 1.目标 :实现和探索具有一个变量的线性回归的成本函数. import numpy as np %matplotlib wi ...
- java多线程--7 线程协作 线程池
java多线程--7 线程协作 线程池 并发协作模型--生产者消费者模式 这是一个线程同步问题,生产者和消费者共享同一个资源,并且生产者和消费者之间互相依赖,互为条件. java提供了几个方法解决线程 ...
- 小知识:IN和EXISTS的用法及效率验证
环境: Oracle 19.16 多租户架构 经常会在网上看到有人写exists和in的效率区别,其实在新版本的数据库中,是不存在这个问题的,优化器会自己判断选择最优的执行计划. 为了直观的说明,我在 ...
- w11修改ie保护模式方法
IE安全设置下有4个区域 对应的设置在不同的注册表中.[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Set ...
- [Linux]CentOS7:卸载、安装Java JDK
JDK(Java Development Kit)是Java语言的软件开发工具包,包括Java运行环境.Java开发工具.Java基础类库. JRE(Java Runtime Environment) ...
- Redis缓存高可用集群
作者:京东零售 王雷 1.Redis集群方案比较 • 哨兵模式 在redis3.0以前的版本要实现集群一般是借助哨兵sentinel工具来监控master节点的状态,如果master节点异常,则会做主 ...
- day18:json模块&time模块&zipfile模块
json模块 1.关于json的定义 所有的编程语言都能够识别的数据格式叫做json,是字符串能够通过json序列化成字符串与如下类型: (int float bool str list tuple ...
- 通过 iframe 调用 天气预报&jsonp
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- RDIFramework.NET WinForm版新增报表管理功能模块
在Web版本中有报表管理功能模块,非常实用的功能,重量级推荐.在WinForm应用中,我们也增加了支持."报表管理"模块主要用于对日常常用的报表做定制展示,可以自动发布到模块,同时 ...