Vue 3.x与Vue 2.x版本拦截器的对比详解(Vue数据拦截器)
作者:不吃泡面~
数据拦截本身定义
我们对数据进行读写操作时,需要一种机制,能够打断读写操作进行额外的新操作,灵活高效率,这种机制叫做数据拦截。
数据拦截的应用:
Vue和React的组件生命周期钩子函数,本质上就是数据拦截。可以在组件初始化到组件完全渲染出来的时间线里,设置拦截,方便在特定时间进行相关操作。
JS中的数据拦截
主要有两种方式:
- Object.defineProperty:用于Vue 1.x、Vue 2.x
- Proxy:用于Vue 3.x
Object.defineProperty 拦截API
Object.defineProperty 是Object上的一个静态方法,作用是给一个对象添加新的属性,还能给该属性进行相关配置。
Object.defineProperty(obj, prop, descriptor)
obj:要定义属性的对象;
prop:一个字符串或者Symbol,指定了要定义或者修改的属性键;
descriptor:属性描述符。
属性描述符可以进行相关详情配置:
get取值函数,默认为undefined;
set存值函数,默认为undefined;
value设置属性值,默认值为undefined;
writable:设置属性值是否可写,默认为false;
enumerable设置属性是否可枚举,默认为false;
configurable是否可以配置该属性,默认为false:
该属性的类型是否能在数据属性和访问器属性之间更改;
该属性是否能删除;
描述符的其他属性是否能被更改。
默认情况下,使用 Object.defineProperty( ) 添加的属性是不可写、不可枚举和不可配置的。
Object.defineProperty拦截例子:
function Student() {
let stuName = "张三";
Object.defineProperty(this, "name", {
get() {
return stuName;
},
set(value) {
if (!isNaN(value)) {
stuName = "张三";
} else {
stuName = value;
}
},
});
}
const stu = new Student();
console.log(stu.name);
stu.name = "李四";
console.log(stu.name);
stu.name = 100;
console.log(stu.name);Proxy 拦截API
是ES6新增的API,通过创建代理对象的方式进行拦截。
const p = new Proxy(target, handler)
target:目标对象,可以是任何类型的对象,包括数组,函数。
handler:定义代理对象的行为。
返回值:返回值为一个代理对象,之后外部对属性的读写都是针对代理对象进行操作。
Proxy拦截例子:
function proxyStudent() {
const obj = {
name: "aaa",
};
return new Proxy(obj, {
get(obj, prop) {
return obj[prop] + "是个gay!!!";
},
set(obj, prop, value) {
if (!isNaN(value)) {
obj[prop] = "ggg";
} else {
obj[prop] = value;
}
},
});
}
const p = new proxyStudent();
console.log(p.name);
p.name = "萨克";
console.log(p.name);
p.name = "111";
console.log(p.name);两个之间的不同点
1. 拦截的广度:
Object.defineProperty:是针对 对象特定属性 进行读写操作。
如果用Object.defineProperty,后期新增的对象属性是拦截不到的。
Proxy:是针对 整个对象 进行多种操作。包括*属性的读取、赋值、属性的删除、属性描述符的获取和设置、原型的查看、函数调用等行为*能够进行拦截。
后期新增的对象属性都可以拦截到。
function proxyHandle(obj) {
return new Proxy(obj, {
get(obj, prop) {
console.log(`触发get读取操作,读取到了${prop}属性`);
if (typeof obj[prop] === "object") {
return deepProxy(obj[prop]);
}
return obj[prop];
},
set(obj, prop, value) {
console.log(`触发set写入操作,且开始设置${prop}属性`);
if (typeof value === "object") {
return deepProxy(value);
}
obj[prop] = value;
},
setPrototypeOf(obj, proto) {
console.log("触发拦截设置原型的操作,开始设置原型!");
return Object.setPrototypeOf(obj, proto);
},
getPrototypeOf(obj) {
console.log("触发拦截读取原型的操作!");
return Object.getPrototypeOf(obj);
},
deleteProperty(obj, prop) {
console.log(`触发了删除拦截操作,且删除${prop}属性`);
delete obj[prop];
},
});
}2. 性能上的差异:
各有利弊,对于操作类型简单,是某个特定属性时,Object.defineProperty性能最佳。
只针对某个特定属性的拦截场景较少,一般都是需要针对一个对象的所有属性进行拦截
此时如果需要拦截的对象结构复杂(如需要递归到嵌套对象)或者需要拦截的操作种类繁多,那么使用这种方式就会变得复杂且效率低下。
所以综上来说,大多数情况下,Proxy 是高效的,性能差异是有前提的,看具体的场景。
两个之间的共同点
1. 都可以针对对象成员的读写操作进行拦截:
Object.defineProperty:
const obj = {};
let text = "this is a text";
Object.defineProperty(obj, "content", {
get() {
console.log("此时已经触发拦截器get操作");
return text;
},
set(value) {
console.log("触发拦截器set操作");
text = value;
},
});
obj.content = "abcd";
console.log(obj.content);Proxy:
const obj = {
content: "this is a text",
title: "titleA",
};
const pxy = new Proxy(obj, {
get(obj, prop) {
console.log("数据读取操作拦截到了");
return obj[prop];
},
set(obj, prop, value) {
console.log("触发拦截器set操作");
obj[prop] = value;
},
});
console.log(pxy.content);
pxy.title = "titleB";
console.log(pxy.title);2. 都能进行深度遍历拦截:
Objcet.defineProperty:
function deepObjectDefineProperty(obj) {
for (let key in obj) {
if (obj.hasOwnProperty(key) && typeof obj[key] === "object") {
deepObjectDefineProperty(obj[key]);
}
let _value = obj[key];
Object.defineProperty(obj, key, {
get() {
console.log("触发get读取操作");
return _value;
},
set(value) {
console.log("触发set写入操作");
_value = value;
},
configurable: true,
enumerable: true,
});
}
}
const data = {
obj1: {
obj2: {
val: "this is a data",
},
},
};
deepObjectDefineProperty(data);
console.log(data.obj1.obj2.val);
data.obj1.obj2.val = "this is a value";Proxy:
function deepProxy(obj) {
return new Proxy(obj, {
get(obj, prop) {
console.log("get读取操作触发了");
if (typeof obj[prop] === "object") {
return deepProxy(obj[prop]);
}
return obj[prop];
},
set(obj, prop, value) {
console.log("set写入操作触发了");
if (typeof value === "object") {
return deepProxy(value);
}
obj[prop] = value;
},
});
}
const data = {
obj1: {
obj2: {
val: "this is a data",
},
},
};
const proxyData = deepProxy(data);
console.log(proxyData.obj1.obj2.val);
proxyData.obj1.obj2.val = "this is a text";总结
到此这篇关于Vue 3.x与Vue 2.x版本拦截器对比的文章就介绍到这了,更多相关Vue数据拦截器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
