在背八股的时候,大家都会背上几句,vue2是通过Object.defineProperty来实现响应式原理的,而vue3是通过Proxy来实现的。
然后看上里面的几种方法,并没有过多的去深究。当然我也差不多啦,所以特地的去看了一下,那么废话少说。
1. Proxy是什么
Proxy
是 ES6 引入的特性,可以创建一个对象的代理,拦截并自定义对象的基本操作(如属性访问、赋值、函数调用等)。
基本语法
创建proxy:
js
const proxy = new Proxy(target, handler);
target
:要代理的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理))。handler
:一个对象,内部属性通常为函数,其函数定义了执行各种操作时的行为。
例子:
js
const obj={
name:'lihua',
age:18
}
const handler={
get(obj,prop){
console.log('触发get');
return prop in obj? obj[prop] : 233
},
set(obj,prop,value){
console.log('触发set');
obj[prop]=value
return ture
},
}
const proxy=new Proxy(obj,handler)
console.log(proxy.name);// 触发get lihua
console.log(proxy.age);// 触发get 18
proxy.name='zhangsan'// 触发set
console.log(proxy.name);//触发get zhangsan
这里set不返回bool值会报错
从中还可以看出,Proxy代理的是整个对象,而不是对象的某个属性。
2.proxy的功能
支持proxy这些功能的当然就是陷阱函数,可以对不同的操作进行拦截。
除了get和set,还有很多种不同的陷阱函数,详细的可以去mdn上看,这里列举几种常见的
has
拦截in
操作符
参数:
target
:被代理的目标对象。prop
:检查是否存在的属性名(可以是字符串或 Symbol)。
prop的含义根据陷阱函数不同而不同,其他参数还有很多,如value表示属性值等
js
const obj={
name:'lihua',
age:18
}
const handler={
has(target,prop){
console.log('触发has');
return Reflect.has(target,prop)//Reflect.has(target,prop)会返回true或者false
}
}
const proxy=new Proxy(obj,handler)
console.log("name" in proxy)// 触发has true
apply
拦截函数调用
参数:
target
:被代理的目标函数。thisArg
:调用时的this
值。argumentsList
:传递给函数的参数数组。
js
function sum(a, b) {
return a + b;
}
const handler = {
apply(target, thisArg, argumentsList) {
console.log(`触发apply`);
return Reflect.apply(target, thisArg, argumentsList);
}
};
const proxy = new Proxy(sum, handler);
console.log(proxy(2, 3)); // 触发apply 5
其他的陷阱函数还有deleteProperty(target, prop)
拦截delete,construct(target, args)
拦截new操作符等等
3. 与defineProperty的区别
可动态添加属性
defindeProperty
只能对已经存在的属性进行拦截,无法动态拦截新增的属性
而Proxy
可以:
js
const obj = {}
const handler = {
set(target,prop,value){
console.log('触发set');
target[prop]=value
return true
}
}
const proxy = new Proxy(obj, handler)
proxy.name='zhangsan'// 触发set
console.log(proxy.name);// zhangsan
可以拦截更多操作
defineProperty
只能拦截get
和set
,无法拦截其他操作 但是Proxy
提供了多种陷阱,可以拦截更多操作
- 属性访问(
get
)、赋值(set
) - 删除属性(
deleteProperty
) - 检查属性是否存在(
has
) - 构造函数调用(
construct
) - 函数调用(
apply
)
数组的支持
defineProperty
不能对push
、pop
,等操作以及数组长度变化
等进行拦截 但是Proxy
可以拦截数组的所有操作,包括长度变化和索引访问
js
const arr = [];
const proxy = new Proxy(arr, {
set(target, prop, value) {
console.log('触发set');
target[prop] = value;
return true;
}
});
proxy.push(10); // 触发set
console.log(proxy); // 触发set 10
proxy.push(20)//触发set
console.log(proxy); // 触发set 10,20
proxy.pop()//触发set
console.log(proxy);// 触发set 10
4.不足
兼容性问题
Proxy
是 ES6 引入的新特性,在一些老旧环境中可能不被支持(如 IE 浏览器)。
无法代理原始值
Proxy
只能代理对象(包括数组、函数等),无法直接代理原始值(如数字、字符串、布尔值),如果需要代理原始值,可以将其包装在一个对象中。