ES6代理中的set、get、has、deleteProperty陷阱

什么是代理

代理(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构造函数需要两个参数:

  1. 目标(target)
  2. 处理程序(Handler)

处理程序是一个或者多个陷阱函数,如果没有使用处理程序,相当于简单的转发代理

如下代码定义一个代理

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陷阱需要传入四个参数:

  1. trapTarget 接收属性(代理的目标)的对象
  2. key 要写入的属性键
  3. value 要写入属性的值
  4. receiver 操作发生的对象

代码示例如下:

//声明被代理对象
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陷阱接受三个参数:

  1. trapTarget 接收属性(代理的目标)的对象
  2. key 要读取的属性键
  3. receiver 操作发生的对象

代码示例如下:

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陷阱需要两个参数:

  1. trapTarget 接收属性(代理的目标)的对象
  2. key 要读取的属性键

示例代码如下:

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陷阱,需要传入两个参数:

  1. trapTarget 接收属性(代理的目标)的对象
  2. key 要读取的属性键

示例代码如下:

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;

你可能感兴趣的:(前端,ES6)