Proxy 字面意思是代理
在这里指的是 拦截 , 可以理解为一个关卡,每次外界对目标对象进行访问时,都必须拦截一下,它可以对外界的访问进行过滤或者改写
Proxy 的语法:
var proxy = new Proxy(targetobj,handler)每次用的时候先是实例化一下
targetobj 指的是要拦截的目标对象
handler 也是一个对象,它主要是用来定制拦截的行为,是读取还是设置以及返回些什么
首先做个读取设置的拦截 例1:
var proxy = new Proxy({}//参数一, { // 参数二
get (target,key, receiver){ // target 指的是当前的对象,这里指的空对象,key指的是调用proxy实例时的属性名 receiver指的是实例本身(属于可选参数)
console.log('得到了'+key+'!')
},
set(target, key,value,receiver){
console.log('设置了'+key+'!')
}
})
proxy.name='wanghongting' // 设置
++proxy.age // 得到 再设置
打印的结果是: 设置了name! 得到了age! 设置了age!
下面只做个读取的拦截 例2:
var proxy = new Proxy({}, {
get: function(target, property) {
return '师父';
}
});
console.log(proxy.name) // ‘师父’
console.log(proxy.worship) // '师父'
console.log(proxy.respect) // '师父'
上面因为拦截函数每次返回的都是师父 所以访问任何属性都得到师父
下面这个例子可以和上面的例2做个比较 例3:
var obj= {
name: 'wht',
worship:'爸爸',
respect: '大哥'
}
var proxy = new Proxy(obj, {
get: function(target, property) {
return target[property];
}
});
console.log(proxy.name) // ‘wht’
console.log(proxy.worship) // '爸爸'
console.log(proxy.respect) // '大哥'
上面因为拦截函数返回target[property] 所以访问到对象对应的属性值
下面这个例子 是当返回的是当前对象的属性值,但其中有的属性名 不是当前对象的属性时 例4
var parson = {
name: 'gaochengxuan',
like: 'eat'
}
var proxy = new Proxy(parson, { // parson 传入的是要拦截的对象
get: function (target, property, receiver) { // 第一个参数target 指的是:当前对象(parson)
第二个参数property指的是调用时传入的属性名字
第三个参数receiver指的是:proxy实例本身(可选参数)
if (property in target) {
return target[property] // 如果当前对象中属性名有你传入进来的 就返回对应的属性值
反之报错 说这个不存在 exist存在的意思
} else {
throw new ReferenceError('这个属性' + property + '是不存在的')
}
}
})
console.log(proxy.name) // 'gaochengxuan'
console.log(proxy.like) // 'eat'
console.log(proxy.age) //'这个属性age不存在'
get方法的可以继承 例5:
let proto = new Proxy({}, { // 也可以传入一个空对象
get(a,b,c){
console.log('hello'+b) // a 空对象 b 调用时传入的属性名 name age foo
return a[b]
}
})
proto.name // 'helloname
proto.age // 'helloage
let obj = Object.create(proto) // 把这个对象复制了一份
obj.foo // ‘hellofoo'
obj.name // 'helloname'
obj.age// 'helloage'
使用get拦截 实现数组读取索引对应的数据 例6:
function createArray(...el){
let target = el;// 这里要解释下 为什么不直接传入el因为它是创建的数组,传过来时默认会把它当作el这个变量,而不会去深究它是否通过创建成数组了
target.push(...el)
return new Proxy(target, {
get(target, propkey, receiver){
let index = Number(propkey)
if(index < 0){
propkey = String(target.length + index) //加不加string 影响不大
}
return target[propkey]//相当于targte.propkey
}
})
}
let arr = createArray('红雨','红方','红婷','love');
console.log(arr[-1]) // love console.log(arr[0]) //'红雨'
说明一下new Proxy 接受两个参数 new Proxy(第一个参数(当前你要拦截的对象),第二个参数是一个对象{ 里面有方法 get(参数一还是当前对象,参数二当前调用new Proxy时传入的属性名,接受的) {这里面是一系列的操作}
proxy还可以实现链式操作 如下 例7:
var chain = (function () { // 匿名函数自执行
return function (value) { // 下面的chain(3)其实就是执行 这个函数
var funcStack = [];
var oproxy = new Proxy({}, {
get: function (pipeObject, fnName) { //fnName指的是 调用时传入的属性名 可以连着调用
if (fnName === 'gets') {
//条件为get
//console.log(funcStack) 数组 里面放着下面的三个函数[f,f,f]
return funcStack.reduce(function (val, fn) {
console.log(val, 'val')
//val指的是 doblue 一开始传入的参数 执行的结果
// pow执行结果 成为reverseInt的参数
//fn指的是下面double pow reverseInt的函数体
return fn(val);
}, value); // value指的是每次结果的基数 传3就是3 传[]就是数组 传对象就是对象
}
funcStack.push(window[fnName]) // 函数名 window[fnName] 对应的是函数体
return oproxy;
}
});
return oproxy;
}
}());
// 下面这些都是方法
var double = n => n * 2;
// 相当于调用当前函数 var double = fucntion (n){return n*2}
var pow = n => n * n;
function ting(n) {
return n + 12
}
var reverseInt = n => n.toString().split("").reverse().join("") | 0;
// 官网这么写的 个人觉得可以去掉 toString()
// 相当于
//console.log(reverseInt(36))
console.log(chain(3).double.pow.ting.reverseInt.gets) // 调用顺序 打印的是最后执行的结果 double先执行n*2 成6 pow再执行n*n 成36 ting最后执行n+12 成48