面试时,我们说完Vue响应式原理,或者Vue2和Vue3的区别时,通常会引出Vue3使用了Proxy来优化响应式,而面试官会继续深挖:说说Proxy与Object.defineProperty的区别。
我们不能只说Proxy直接代理一个对象,这只是一个表层表现,我们需要说出更深层的东西。
下面我们来看一下他们的用法和区别吧。
Proxy
对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举等)
基本语法:
/*
* target: 目标对象
* handler: 配置对象,用来定义拦截的行为
* proxy: Proxy构造器的实例
*/
let proxy = new Proxy(target,handler)
get set
来拦截住我们的读取赋值操作。那Proxy会捕获到我们更深层次的get set吗?
答案是 不会
我们这里读取a 里面的 b属性
发现只能捕获到a这个属性,说明proxy
只会浅层拦截,我们需要拦截整个对象还需要手动地去实现,
我们只需要在读取的时候判断读取的值是不是一个对象,然后递归的去代理即可。
bject.defineProperty()
直接在对象上定义新属性,或修改对象上的现有属性,然后返回该对象。
基础语法:
/*
* obj: 要在其上定义属性的对象
* prop: 要定义或修改的属性的名称或Symbol
* descriptor: 定义或修改的属性的描述符
*/
Object.defineProperty(obj, prop, descriptor)
var obj = {}
Object.defineProperty(obj,'name',{
value:'张三'
}
obj.name // '张三'
obj.name = '李四' // 给obj.name赋新值
console.log(obj.name) // 输出:张三 ,值还是没有改变,因为默认不可写
一次只能代理一个属性值,如果我们要代理整个对象需要在创建时递归地去给所有属性值添加上get set
const obj = {};
let initValue = 1;
Object.defineProperty(obj, 'name', {
set: function(value) {
console.log('set方法被执行了');
initValue = value;
},
get: function() {
return initValue;
}
});
console.log(obj.name); // 1
obj.name = []; // 会执行set方法,会打印信息
// 给 obj 中的name属性 设置为 数组 [1, 2, 3], 会执行set方法,会打印信息
obj.name = [1, 2, 3];
// 然后对 obj.name 中的某一项进行改变值,不会执行set方法,不会打印信息
obj.name[0] = 11;
// 然后我们打印下 obj.name 的值
console.log(obj.name);
// 然后我们使用数组中push方法对 obj.name数组添加属性 不会执行set方法,不会打印信息
obj.name.push(4);
obj.name.length = 5; // 也不会执行set方法
我们对数组某一项值进行修改的时候是无法监听到set属性的,我们在Vue中不能简单的使用obj.name[0] = newValue
,但是vue重写了修改数组的方法
‘push’,
‘pop’,
‘shift’,
‘unshift’,
‘splice’,
‘sort’,
‘reverse’