携手创作,共同成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情 >>
一、Proxy 对象代理
Proxy 代理目标对象,换种理解方式便是拦截对象的所有操作,类似:取值,设置值等等。Proxy 代理一个对象,是直接监听整个对象,而非 Object.defineProperty 只是监听对象的 get 与 set。
Proxy(target, handler)
let ProxyObj = Proxy({
// 代理对象属性
id: 1,
name: '‘你好
},{
// 代理方法
// obj:代理的对象 prop:被查询的值
get(obj, prop){
console.log(`${prop}被查询`)
},
// value: 被设置的新值
set(obj, prop, value){
console.lgo(`${prop}的值被修改为${value}`)
return obj[prop] = value
}
})
Tips:一旦对象被代理之后,对象的 this 就指向了代理对象。
1. Proxy 都能干什么?
- get()
get() 方法用于拦截某个属性的读取操作,接受三个参数,依次为目标对象、属性名和 proxy 实例本身(可选属性)。
- set()
set() 方法用来拦截某个属性的赋值操作,接受四个参数,依次为目标对象、属性名、属性值和 Proxy 实例本身(可选属性)。
- apply()
- 函数对象也可以作为代理的目标对象。apply() 方法拦截函数的调用、call 和apply 操作。
- apply() 方法可以接受三个参数,分别是目标对象、目标对象的上下文对象(this)和目标对象的参数数组。
- construct()
construct 拦截的是 new 操作,接受三个参数:目标对象,构造函数的参数对象,创造实例对象时,new 命令作用的构造函数。
Tips:Proxy 常用的两个方法其实就 get() 和 set() 两个,用来做双向数据绑定和数据响应式。
二、Object.defineProperty 监听对象属性
Object.defineProperty 用于劫持并监听对象属性的某些操作。
Object.defineProperty(target, props, handler)
let obj = {
username: "",
};
// 三个参数:
// 1. 要操控的对象。
// 2. 要操作的属性。
// 3. 设置具体方法。
// 其原理就是对数据进行劫持,设置数据的每次取值和修改值时都得通过 Object.defineProperty
Object.defineProperty(obj, "username", {
// 使用 Object.defineProperty 劫持对象的 get 与 set 方法
// get 方法监听对象的取值操作
// 也就是说只要输出或者调用了 obj.username 都会触发 get 方法
// 比如输出:console.log(obj.username) 和
// 赋值:let a = obj.username 都会触发 get方法
get: function () {
console.log("取值操作");
console.log(obj.username);
},
// set 方法监听对象的修改、设置值操作
// 例:obj.username = xxx 就会触发 set
set: function (value) {
console.log("对象值被修改");
// 动态更新文本值
document.getElementById("userName").innerText = value;
},
});
三、两者区别
1. Proxy():
- 针对整个对象,而不是对象的某个属性
- 不需要对数组的方法进行重载,省去了众多 hack
- 不需要遍历对象的每个属性
- 不需要深层遍历嵌套的对象
- get 里面递归调用 Proxy 并返回
- 性能消耗低,但浏览器兼容性低
2. Object.defineProperty():
- 针针对对象的属性。
- 不能监听数组的变化。
- 必须遍历对象的每个属性。
- 必须深层遍历嵌套的对象。
- 性能消耗高,但浏览器兼容性高。
3. 总结:
总得来说,Proxy 代理整个对象,而不只是去监听对象的某个属性,且支持对数组的代理,但是兼容性不高,也是 Vue3 才会使用 Proxy 实现双向绑定的一个原因。