在实际开发中常常会遇到js抛出的错误,可是咱们有没有想过本身去接管js异常验证,根据本身的需求抛出异常呢?本来也许不行,可是在es6出来后就能够作到了es6
什么是‘代理’ 呢?代理:就是调用new 建立一个和目标(traget)对象一直的虚拟化对象,然该代理中就能够拦截JavaScript引擎内部目标的底层对象的操做;这些底层操做被拦截后会触发响应特定操做的陷阱函数
来看个简单的案例api
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对象API;该对像中的方法默认特性与底层的操做对应;而每个代理陷阱会对应一个命名和参数都相同的Reflect方法(其实就是每一个代理陷阱都会对应一个Reflect api接口供覆写JavaScript底层操做)app
映射关系以下表:函数
代理陷阱 | 覆写的特性 | 默认特性 |
---|---|---|
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陷阱来验证一下对象属性赋值操做(如为对象新增属性,要求必须赋值为int)测试
let target = { name :'target' }; let proxy = new Proxy(target,{ set(trapTarget,key,value,receiver){ //忽略不但愿受到影响的已有属性 if(!trapTarget.hasOwnProperty(key)){ if(isNaN(key)){ 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陷阱默认接收 四个参数this
如spa
let target = {}; console.log(target.name); // undefined
在JavaScript中调用一个对象不存在的属性不会报错,反而使用undefined代替被读取属性的值代理
而喝多时候会带来意想不到的bug,如今咱们可使用get陷阱来验证该问题
依然看这个案例code
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)
参数
使用这个两个陷阱来验证函数调用时的参数的正确性
以下案例
// 参数求和 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()都接受一样的参数
当使用new调用函数时 会触发construct陷阱,接收的参数为
其中Reflect.construct()第三个参数是newTarget 这是一个可选参数。用于指定该函数内部
new.target的值
看到这里有没有感受这个对于js项目代码检测仍是蛮有用处的呢。 ok先到这里,时间不早了改且休息了;改天继续…