JavaScript中的代理

372 阅读3分钟

Proxy也就是代理,是ES6为开发者提供了拦截并向基本操作嵌入额外行为的能力。说人话就是在对一个目标对象进行访问设置等等操作前,添加了一层拦截,在这层拦截中你可以为所欲为,定义你想要的效果,懂我意思吧?

语法

const p = new Proxy(target, handler)

target:被Proxy包装的目标对象。

handler:一个对象,其属性是用于代理的Trap函数,当对目标对象进行操作时候触发指定的某个Trap函数。

使用例子

let test = {
	name:'熊猫',
};
test = new Proxy(test , {
	get(target,key) {
		console.log('访问test对象中属性值的时候被我拦截咯')
		console.log(target) // { name:'熊猫' }
		console.log(key)  // name
		return target[key] 
	}
});

console.log(test.name) //熊猫

上面的例子中,我们首先创建了一个test对象,里面有name属性。然后我们使用Proxy将其包装起来,再返回给test,此时的test已经成为了一个Proxy实例,我对其的操作,都会被Proxy拦截。

Proxy中有两个参数,第一个参数是target,传入的值也就是我们上面那个test对象。第二个参数是handler,里面都是一个个函数,俗称Trap。每对目标函数进行一种操作会触发对应的一个Trap函数。比如我对目标对象进行获取操作就是触发get函数。对目标函数的某个属性进行赋值操作,就会触发set函数。 我们这里就写了一个get函数,其实还有很多Trap函数。(可以点下去了解每个Trap函数的参数及其用法)

可以看到,最后一句我们获取test对象中属性name,并再控制台中输出值的过程中被Proxy拦截了下来,触发了位于handler对象中的get函数。

使用例子

理解了上面的部分我们再来看一个例子

let test = {
	name:'熊猫',
	id:'111'
};
test = new Proxy(test , {
	get(target,key) {
		return target[key] 
	},
     set(target,key,value){
         if ( key==='id' && typeof value!== "string" ) {
         		throw Error('id字段必须为字符串类型')
         }
         target[key] = value
         return true
      }	
});

console.log(test.name) //熊猫
test.id = 222 

先是对目标函数的name属性值进行获取并输出到控制台的操作,被Proxy拦截了下来,触发了handler对象中的get函数。再来进行目标函数属性值的重新赋值,被Proxy拦截了下来,触发了handler对象中的set函数,在set函数中对赋值给属性的值类型进行了判断,如果不是字符串类型则抛出异常。反之则是字符串类型,进行赋值,成功返回true,失败返回false。

Reflect

上面第二个例子也可以这么写

...
     set(target,key,value){
         if ( key==='id' && typeof value!== "string" ) {
         		throw Error('id字段必须为字符串类型')
         }
         return Reflect.set(target,key,value)
      }	
...

在set函数中对赋值给属性的值类型进行了判断,如果不是字符串类型则抛出异常。反之则是字符串类型,执行Reflect的set函数。

这个Reflect是一个内置的对象,它提供拦截JS操作的方法。这些方法与proxy handlers的方法相同。

具体Reflect中的函数怎么用和handlers中函数的区别,可以点击这个查看Reflect


附上原文JS Proxy(代理) 漫思