什么是代理
代理(proxy)是一种包装器,可以拦截 并改变javascript引擎的操作。
通过下面这段程序来理解代理要解决的问题:
let colors = ["red", "blue", "green"];
console.log(colors.length);// 3
console.log(colors[0]);// red
console.log(colors[1]);//blue
colors[3] = "black";
console.log(colors.length); //4
colors.length = 2;
console.log(colors.length);// 2
console.log(colors[2]);// undefined
console.log(colors[1]);// blue
在ES5之前,开发者没法定义一个对象可以模仿数组这些行为,这些都是js引擎在做的这。但是,现在通过ES6的代理完全可以做这些事情,这便是代理存在的意义。
创建一个简单的代理
Proxy构造函数需要两个参数:
处理程序是一个或者多个陷阱函数,如果没有使用处理程序,相当于简单的转发代理
如下代码定义一个代理
let target = {};
let proxy = new Proxy(target, {});
proxy.name = "proxy";
console.log(proxy.name);// "proxy"
console.log(target.name);// "proxy"
target.name = "target";
console.log(proxy.name);// "target"
console.log(target.name);// "target"
上述代码没有加入陷阱函数,只是一个简单的代理转发。
接下来看几个常见的代理陷阱
set陷阱验证属性
set陷阱需要传入四个参数:
代码示例如下:
//声明被代理对象
let target = {
name: "target"
};
//声明代理对象,并加入set陷阱
let proxy = new Proxy(target, {
//这里便是set陷阱函数
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(target.count);// 1
proxy.name = "Proxy";
console.log(proxy.name); // "Proxy"
console.log(target..name);// "Proxy"
//这里给代理加入的属性不存在目标中,值也不为数字,所以会抛出错误
proxy.anotherName = "proxy";
get陷阱验证对象结构
js有一个令人疑惑的地方,读取不存在的属性时,不会报错,而是返回undefined。
现在,可以通过get陷阱函数来改写js引擎的行为,让程序在读取不存在的属性时报错。
get陷阱接受三个参数:
代码示例如下:
let proxy = new Proxy({},{
get (trapTarget,key,receiver){
if(!(key in receiver)){
throw new TypeError("属性"+key+"不存在");
}
return Reflect.get(trapTarget,key,receiver);
}
})
proxy.name = "proxy";
console.log(proxy.name); //"proxy"
console.log(proxy.nme);//抛出错误
这里没有使用target对象,为了防止receiver代理含有has陷阱
使用has陷阱隐藏已有属性
has陷阱需要两个参数:
示例代码如下:
let target = {
name: "target",
value: 42,
};
let proxy = new Proxy(target, {
has(trapTarget, key){
if(key === "value"){
return false;
}else{
return Reflect.has(trapTarget, key);
}
}
});
console.log("value" in proxy);// false
console.log("name" in proxy);// true
console.log("toString" in proxy);//true
用deleteProperty陷阱防止删除属性
每当使用delete操作,都会调用deleteProperty陷阱,需要传入两个参数:
示例代码如下:
let target = {
name: "target";
age: 42
}
let proxy = new Proxy(trapTarget, {
deleteProperty(trapTarget, key){
if(key === "value"){
return false;
}else{
return Reflect.deleteProperty(trapTarget, key);
}
}
});
//尝试删除proxy.value
console.log("value" in proxy); //true;
let result1 = delete proxy.value;
console.log( result1);//false;
console.log("value" in proxy); //true;
//尝试删除proxy.name
console.log("name" in proxy); //true;
let result2 = delete proxy.name;
console.log( result2);//true;
console.log("name" in proxy); //false;