vue3和vue2数据代理的区别
前言
在Vue 2中,使用Object.defineProperty方法进行数据代理。这种方法通过在对象上定义getter和setter来拦截对数据的访问和修改。当访问或修改对象的属性时,Vue会在底层执行一些操作,以便触发数据的变化侦测和响应式更新。
然而,在Vue 3中,使用了Proxy对象进行数据代理。Proxy是ES6引入的一种新特性,它可以拦截并自定义对对象的操作。通过使用Proxy,Vue 3能够更好地追踪数据的变化。
Object.defineProperty存在问题
1. 由于Object.defineProperty()对对象的属性只是进行读取和修改,所以当新增属性或者删除属性页面不会更新。
<template>
<div class="box">
<div>
<span>姓名:{{ person.name }}</span>
<span>年龄:{{ person.age }}</span>
<span>性别:{{ person.sex }}</span>
</div>
<div class="box-button">
<el-button @click="deleteAge">删除年龄</el-button>
<el-button @click="addSex">添加性别</el-button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
person: {
name: "小明",
age: 18,
},
hoppy: ["打球", "睡觉"],
};
},
methods: {
// 点击删除年龄
deleteAge() {
delete this.person.age;
console.log(this.person.age)
},
// 点击添加性别
addSex() {
this.person.sex = "女";
console.log(this.person.sex);
},
},
};
</script>
这里分别向person对象中添加了性别和删除了年龄,可以看出数据发生变化,但是视图并没有更新。
解决方案:vue提供了$set
和$delete
两个实例方法,让开发者通过这两个实例方法对已有响应式对象添加或删除属性;
methods: {
// 点击删除年龄
deleteAge() {
this.$delete(this.person, "age");
},
// 点击添加性别
addSex() {
this.$set(this.person, "sex", "女");
},
},
2. 同样直接通过下标更改数组页面不会更新;
<template>
<div class="box">
<span>爱好:{{ hoppy }}</span>
<div class="box-button">
<el-button @click="changeHoppy">更改爱好</el-button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
hoppy: ["打球", "睡觉"],
};
},
methods: {
// 修改爱好
changeHoppy() {
this.hoppy[0] = '学习'
console.log(this.hoppy);
},
},
};
</script>
这里通过下标的方式修改数组,数据发生变化,但是视图没有更新。
解决方案:这里可以通过$set方法触发视图更新,也可以通过splice方法触发视图更新。
methods: {
// 修改爱好
changeHoppy() {
this.hoppy.splice(0, 1, '学习')
this.$set(this.hoppy, 0, "学习");
},
},
Proxy
同样是上面的例子🌰,换成vue3中。
<template>
<div class="box">
<span>姓名:{{ person.name }}</span>
<span>年龄:{{ person.age }}</span>
<span>性别:{{ person.sex }}</span>
<span>爱好:{{ person.hoppy }}</span>
</div>
<div class="box-button">
<el-button @click="deleteAge">删除年龄</el-button>
<el-button @click="addSex">添加性别</el-button>
<el-button @click="changeHoppy">更改爱好</el-button>
</div>
</template>
<script setup lang="ts">
import { reactive } from "vue";
interface IPerson {
name: string;
age?: number;
sex: string;
hoppy: string[];
}
const person: IPerson = reactive({
name: "小明",
age: 18,
sex: "",
hoppy: ["打球", "睡觉"],
});
const deleteAge = () => {
delete person.age;
console.log(person.age);
};
const addSex = () => {
person.sex = "女";
console.log(person.sex);
};
const changeHoppy = () => {
person.hoppy[0] = "学习";
console.log(person.hoppy);
};
</script>
当数据发生改变的时候,视图同样会发生改变。
Proxy与Object.definedProperty的优劣对比
Object.defineProperty的劣势:
- 监听不到对象属性的删除和添加,需要借助
$set
和$delete
方法。 - 对于数组的API方法无法监听,vue2中对于数组的方法进行了包裹。
- 对于嵌套对象需要递归深度监听,极大的造成性能浪费。
Object.defineProperty的优势:兼容性好,支持IE9。
Proxy优势:
- Proxy可以直接监听对象而非属性,所以对于对象中属性所有操作都可以监听到。
- Proxy可以直接监听数组的变化。
- Proxy有多达13种拦截方法,不限于apply、ownKeys、deleteProperty、has等等是Object.defineProperty不具备的。
- Proxy返回的是一个新对象,我们可以只操作新的对象达到目的,而Object.defineProperty只能遍历对象属性直接修改
- Proxy作为新标准将受到浏览器厂商重点持续的性能优化,也就是传说中的新标准的性能红利。
Proxy劣势:兼容性不是太好,不兼容IE,且无法通过polyfill提供兼容,因此Vue的作者才声明需要等到下个大版本(3.0)才能用Proxy重写。会改变this指向。
转载自:https://juejin.cn/post/7248545082130546725