has方法可以看作是针对 in 操作的钩子,当我们判断对象是否具有某个属性时,这个方法会生效,典型的操作就是 in ,改方法接收两个参数 目标对象 target 和 要检查的属性 prop,并返回一个 boolean 值。
let p = new Proxy({}, { has: function(target, prop) { if( prop[0] === '_' ) { console.log('it is a private property') return false; } return true; } }); console.log('a' in p); // true console.log('_a' in p ) // it is a private property // false
上述例子中,我们用 has 方法隐藏了属性以下划线_开头的私有属性,这样在判断时候就会返回 false,从而不会被 in 运算符发现~
要注意,如果目标对象的某一属性本身不可被配置,则该属性不能够被代理隐藏,如果目标对象为不可扩展对象,则该对象的属性不能够被代理隐藏,否则将会抛出 TypeError。
let obj = { a : 1 }; Object.preventExtensions(obj); // 让一个对象变的不可扩展,也就是永远不能再添加新的属性 let p = new Proxy(obj, { has: function(target, prop) { return false; } }); console.log('a' in p); // TypeError is thrown
数据绑定
上面介绍了这么多,也算是对 Proxy 又来一个初步的了解,那么我们就可以利用 Proxy 手动实现一个极其简单数据的双向绑定(Object.defineProperty() 的实现方式可以参考我上篇文章的末尾有涉及到)~
主要看功能的实现,所以布局方面我就随手一挥了~
页面结构如下:
<!--html--> <div> <h3></h3> <input type="text"/> </div>
主要还是得看逻辑部分:
//获取段落的节点 const paragraph = document.getElementById('paragraph'); //获取输入框节点 const input = document.getElementById('input'); //需要代理的数据对象 const data = { text: 'hello world' } const handler = { //监控 data 中的 text 属性变化 set: function (target, prop, value) { if ( prop === 'text' ) { //更新值 target[prop] = value; //更新视图 paragraph.innerHTML = value; input.value = value; return true; } else { return false; } } } //添加input监听事件 input.addEventListener('input', function (e) { myText.text = e.target.value; //更新 myText 的值 }, false) //构造 proxy 对象 const myText = new Proxy(data,handler); //初始化值 myText.text = data.text;
上述我们通过Proxy 创建了 myText 实例,通过拦截 myText 中 text 属性 set 方法,来更新视图变化,实现了一个极为简单的 双向数据绑定~
总结
说了这么多 , Proxy 总算是入门了,虽然它的语法很简单,但是要想实际发挥出它的价值,可不是件容易的事,再加上其本身的 Proxy 的兼容性方面的问题,所以我们实际应用开发中使用的场景的并不是很多,但不代表它不实用,在我看来,可以利用它进行数据的二次处理、可以进行数据合法性的校验,甚至还可以进行函数的代理,更多有用的价值等着你去开发呢~
况且,Vue3.0 都已经准备发布了,你还不打算让学习一下?