likes
comments
collection
share

vue3和vue2数据代理的区别

作者站长头像
站长
· 阅读数 37

前言

在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对象中添加了性别和删除了年龄,可以看出数据发生变化,但是视图并没有更新。

vue3和vue2数据代理的区别

解决方案: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>

这里通过下标的方式修改数组,数据发生变化,但是视图没有更新。

vue3和vue2数据代理的区别

解决方案:这里可以通过$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>

当数据发生改变的时候,视图同样会发生改变。 vue3和vue2数据代理的区别

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
评论
请登录