昨天在和群友讨论时遇到一题是这样的。
题目描述
//Tomy非常敏感,不喜欢别人碰他的东西。一旦有人碰他就会大喊Don't Touch Me. //完成tomy这个对象,禁止对tomy的内容进行修改(增加、修改、删除) //一旦有人对tomy进行任何的修改,调用console.log打印Don't Touch Me const tomy={ name:"lizhiqiang", age:"23" };
题目分析
刚开始我觉得可以通过es5中的defineProperty去定义访问器属性,当要修改tomy的属性时,就可以console.log信息出来。
可是这样的话无法做到当要删除属性时,以及要增加属性时,console.log信息。也就是说defineProperty提供给我们的权限还不够,我们需要更加底层的操作。
那么要怎么做呢?
只能使用ES6中的proxy来做啦。
题目要求我们在修改之前console信息,也就是需要我们拦截下修改操作,并在此之前console信息。
proxy简介
通过调用 new Proxy() ,你可以创建一个代理用来替代另一个对象(被称为目标),这个代理对目标对象进行了虚拟,因此该代理与该目标对象表面上可以被当作同一个对象来对待。
代理允许你拦截在目标对象上的底层操作,而这原本是 JS 引擎的内部能力。拦截行为使用了一个能够响应特定操作的函数(被称为陷阱)。
被 Reflect 对象所代表的反射接口,是给底层操作提供默认行为的方法的集合,这些操作是能够被代理重写的。每个代理陷阱都有一个对应的反射方法,每个方法都与对应的陷阱函数同名,并且接收的参数也与之一致。下表总结了这些行为:
好了,针对题目要求,我们只需要写代理陷阱set、deleteProperty就行。
代码
//Tomy非常敏感,不喜欢别人碰他的东西。一旦有人碰他就会大喊Don't Touch Me. //完成tomy这个对象,禁止对tomy的内容进行修改(增加、修改、删除) //一旦有人对tomy进行任何的修改,调用console.log打印Don't Touch Me const tomy={ name:"lizhiqiang", age:"23" }; let tomyProxy=new Proxy(tomy,{ deleteProperty(trapTarget,key){ console.log("Don't Touch Me--delete "+key); return false; }, set(trapTarget, key, value, receiver) { if (!trapTarget.hasOwnProperty(key)) { console.log("Don't Touch Me--add "+key); }else{ console.log("Don't Touch Me--update "+key); } return false; } }); console.log(tomyProxy); Object.freeze(tomyProxy); delete tomyProxy.age;//删除属性 console.log(tomyProxy); tomyProxy.age=1;//修改属性 console.log(tomyProxy); tomyProxy.phone="123456789";//增加属性 console.log(tomyProxy);
运行结果如下,可见这样是可行的。
其实es6的proxy和symbol还有很多值得深入学习的呀,以后会慢慢练习使用。