在实际开发中经常会遇到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)的更多相关文章

  1. 代理(Proxy)和反射(Reflection)

    前面的话 ES5和ES6致力于为开发者提供JS已有却不可调用的功能.例如在ES5出现以前,JS环境中的对象包含许多不可枚举和不可写的属性,但开发者不能定义自己的不可枚举或不可写属性,于是ES5引入了O ...

  2. JAVA设计模式-动态代理(Proxy)源码分析

    在文章:JAVA设计模式-动态代理(Proxy)示例及说明中,为动态代理设计模式举了一个小小的例子,那么这篇文章就来分析一下源码的实现. 一,Proxy.newProxyInstance方法 @Cal ...

  3. [整理]C#反射(Reflection)详解

    本人理解: 装配件:Assembly(程序集) 晚绑定:后期绑定 MSDN:反射(C# 编程指南) -----------------原文如下-------- 1. 什么是反射2. 命名空间与装配件的 ...

  4. 【设计模式】学习笔记17:代理模式之保护代理与Java反射

    本文出自   http://blog.csdn.net/shuangde800 本笔记内容: 1. Java动态代理,反射机制 2. 保护代理 3. 应用保护代理实现的约会系统 ----------- ...

  5. Webpack代理proxy配置,解决本地跨域调试问题,同时允许绑定host域名调试

    Webpack代理proxy配置,解决本地跨域调试问题,同时允许绑定host域名调试 会撸码的小马 关注 2018.05.29 17:30* 字数 212 阅读 1488评论 0喜欢 2 接到上一章, ...

  6. 浅谈Java代理一:JDK动态代理-Proxy.newProxyInstance

    浅谈Java代理一:JDK动态代理-Proxy.newProxyInstance java.lang.reflect.Proxy:该类用于动态生成代理类,只需传入目标接口.目标接口的类加载器以及Inv ...

  7. AGS API for JS代理页的使用

    AGS API for JS代理页的使用 1.概述 代理页即使用后端语言编写的请求转发页面,部署在Web应用端.客户端请求先发送到该代理页,代理页再将该请求转发到服务器处理,服务器处理结果再经代理页转 ...

  8. C#反射(Reflection)详解

    1. 什么是反射2. 命名空间与装配件的关系3. 运行期得到类型信息有什么用4. 如何使用反射获取类型5. 如何根据类型来动态创建对象6. 如何获取方法以及动态调用方法7. 动态创建委托 1.什么是反 ...

  9. JAVA设计模式-动态代理(Proxy)示例及说明

    在Mybatis源码解析,一步一步从浅入深(五):mapper节点的解析文章的最后部分,我们提到了动态代理的概念,下面我们就简单了解一下动态代理. 一,概念 代理设计模式的目的就是在不直接操作对象的前 ...

  10. ArcGIS JS 使用Proxy之 Printing Tools unable to connect to mapServer

    ArcGIS JS使用Proxy.ashx将地图服务隐藏,并在微博服务器端增加了地图服务权限判断. Proxy.ashx做了如下设置, <serverUrl url="http://l ...

随机推荐

  1. Masa Framework源码解读-02缓存模块(分布式缓存进阶之多级缓存)

    序言 ​ 今天这篇文章来看看Masa Framework的缓存设计,上一篇文章中说到的MasaFactory的应用也会在这章节出现.文章中如有错误之处还请指点,咱们话不多说,直入主题. Masa Fr ...

  2. void关键字

    在C++中,void表示为无类型,主要有三个用途: (1)函数的 返回值用void,表示函数没有返回值. void func(int a, int b) { //函数体代码 return; } (2) ...

  3. Rainbond的 Gateway API 插件制作实践

    Gateway API 作为新一代的流量管理标准,对原有 Ingress 的扩展不规范.移植性差等问题做出了改进.从兼容K8s生态和优化网关体验出发,Rainbond 支持以插件的形式扩展平台网关能力 ...

  4. 基于el-input实现数字区间输入框(已发布npm/github)

    项目地址:https://github.com/heyu3913/InputNumberRange  (求star) input-number-range tips:更多定制化需求请联系: 13102 ...

  5. gulp基本操作

    1.安装淘宝镜像 npm install cnpm -g --registry=https://registry.npm.taobao.org cnpm -v 2.生成项目描述文件 package.j ...

  6. odoo 开发入门教程系列-准备一些操作(Action)?

    准备一些操作(Action)? 到目前为止,我们主要通过声明字段和视图来构建模块.在任何真实的业务场景中,我们都希望将一些业务逻辑链接到操作按钮.在我们的房地产示例中,我们希望能够: 取消或将房产设置 ...

  7. MySQL--索引的数据结构

    1.为什么使用索引 索引是存储引擎用于快速找到数据记录的一种数据结构,就好比一本教科书的目录部分,通过目录中找到对应文章的页面,便可以快速定位到需要的文章,mysql中也是一样的道理,进行数据查找时, ...

  8. mysql锁及锁出现总结

    转载请注明出处: 1.按锁粒度分类: 行锁:锁某行数据,锁粒度最小,并发度高:: 行锁是指加锁的时候锁住的是表的某一行或多行记录,多个事务访问同一张表时,只有被锁住的记录不能访问,其他的记录可正常访问 ...

  9. CommunityToolkit.Mvvm8.1 viewmodel源生成器写法(3)

    本系列文章导航 https://www.cnblogs.com/aierong/p/17300066.html https://github.com/aierong/WpfDemo (自我Demo地址 ...

  10. 最新版本 Stable Diffusion 开源 AI 绘画工具之图生图进阶篇

    目录 图生图基本参数 图生图(img2img) 涂鸦绘制(Sketch) 局部绘制(Inpaint) 涂鸦蒙版(Inpaint sketch) 上传蒙版(Inpaint upload) 图生图基本参数 ...