defineProperty和proxy
“数据绑定”这个词是现在市面上流行框架必懂的概念,“数据绑定”的关键在于监听数据的变化,主要的实现方法是defineProperty(数据劫持)和proxy(代理)这两种方法,vue2.0实现数据绑定正是使用前者,vue3.0使用是后者
definePropety
ES5 提供了 Object.defineProperty 方法,该方法可以在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回这个对象。
Object.defineProperty(obj, prop, descriptor)
参数:
obj: 要在其上定义属性的对象。
prop: 要定义或修改的属性的名称。
descriptor: 将被定义或修改的属性的描述符。
双向绑定的例子,当然不可能是只监听一个属性
// obj 这是要劫持的对象 监听的属性值的变化
var obj = {
value:''
}
var value = '';
Object.defineProperty(obj,"value",{
get:function(){
return value
},
set:function(newVal){
value = newVal
}
})
document.querySelector('#input').oninput = function(){
var value = this.value;
obj.value = value;
document.querySelector('#text').innerHTML = obj.value;
}
缺点:
1、只能监听对象(Object),不能监听数组的变化,无法触发push, pop, shift, unshift,splice, sort, reverse。
2、必须遍历对象的每个属性
3、只能劫持当前对象属性,如果想深度劫持,必须深层遍历嵌套的对象。
由上我们知道 Object.defineProperty只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历。Vue 2.x里,是通过 递归 + 遍历 data 对象来实现对数据的监控的,如果属性值也是对象那么需要深度遍历,显然如果能劫持一个完整的对象是才是更好的选择。
Proxy
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。Proxy 的构造函数语法为:
const p = new Proxy(target, handler)
相关的参数说明如下:
target:要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
handler:一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。
handler 对象支持的捕获器
handler 对象支持 13 种捕获器,这里阿宝哥只列举以下 5 种常用的捕获器:
handler.get():属性读取操作的捕获器。 handler.set():属性设置操作的捕获器。
handler.deleteProperty():delete 操作符的捕获器。
handler.ownKeys():Object.getOwnPropertyNames 方法和
Object.getOwnPropertySymbols 方法的捕获器。 handler.has():in 操作符的捕获器。
需要注意的是,所有的捕获器是可选的。如果没有定义某个捕获器,那么就会保留源对象的默认行为。
var proxy = new Proxy({}, {
get: function(obj, prop) {
console.log('设置 get 操作')
return obj[prop];
},
set: function(obj, prop, value) {
console.log('设置 set 操作')
obj[prop] = value;
}
});
proxy.time = 35; // 设置 set 操作
console.log(proxy.time); // 设置 get 操作 // 35
Proxy 的优势如下:
- Proxy 可以直接监听对象而非属性;
- Proxy 可以直接监听数组的变化;
- Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具备的;
- Proxy 返回的是一个新对象,我们可以只操作新的对象达到目的,而 Object.defineProperty 只能遍历对象属性直接修改;
- Proxy 作为新标准将受到浏览器厂商重点持续的性能优化,也就是传说中的新标准的性能红利;
Object.defineProperty 的优势如下:
兼容性好,支持 IE9,而 Proxy 的存在浏览器兼容性问题,而且无法用 polyfill 磨平,因此 Vue 的作者才声明需要等到下个大版本( 3.0 )才能用 Proxy 重写。