Vue2(Object.defineProperty)和Vue3(Proxy和Reflect)响应式原理

2023-12-13 16:00:36

Vue2和Vue3原理:

Vue2响应式实现原理:
对象类型:通过Object.defineProperty()对属性的读取、修改进行拦截(数据劫持)
数组类型:通过重写更新数组的一系列方法来实现拦截(对数组的变更方法进行了包裹)
Object.defineProperty(data, 'count', {
    get() {},
    set() {}
})
Vue2响应式存在问题:
新增属性、删除属性界面不会自动更新
直接通过下标修改数组,界面不会自动更新

具体案例用法如下:
<template>
    <div>
        <div>{{ obj.sex }}</div>
        <div>{{ obj.arr }}</div>
        <button @click="changeSex">sex</button>
        <button @click="deleteSex">deleteSex</button>
        <button @click="changeArr">arr</button>
    </div>
</template>
  
<script>
import Vue from 'vue'
export default {
    name: 'App',
    data() {
        return {
            obj: {
                name: '',
                age: '',
                arr: []
            }
        }
    },
    methods: {
        changeSex() {
            // 不能生效
            // this.obj.sex = '男'

            this.$set(this.obj, 'sex', '男') // 或者Vue.set(this.obj, 'sex', '男')
        },
        deleteSex() {
            // 不能生效
            // delete this.obj.sex

            this.$delete(this.obj, 'sex')
        },
        changeArr() {
            // 不能生效
            // this.obj.arr[0] = '爱学习'

            this.$set(this.obj.arr, 0, '1') // 或者使用this.obj.arr.splice(0, 1, '1')
            this.$set(this.obj.arr, 1, '2') // 或者使用this.obj.arr.splice(1, 1, '2')
        },
    }
}
</script>
  
  
Vue3响应式实现原理:
通过Proxy(代理):拦截对象中任意属性的变化,包括:属性值的读写、添加、删除等
通过Reflect(反射):对被代理对象的属性进行操作

具体案例用法如下:
<template>
  <div>{{ person.sex }}</div>
  <div>{{ person.arr }}</div>
  <button @click="changeSexAndArr">按钮</button>
</template>

<script>
import { reactive } from 'vue'
export default {
  name: 'App',
  setup() {
    const person = reactive({
      name: '张三',
      age: 18,
      job: {
        industry: '前端',
        salary: '30k'
      },
      arr: []
    })

    function changeSexAndArr() {
      person.sex = '男'
      person.arr[0] = 1
      person.arr[1] = 2
      setTimeout(() => {
        delete person.arr
      }, 2000);
    }

    return {
      person,
      changeSexAndArr
    }
  }
}
</script>

模拟Vue2和Vue3实现响应式原理

// person代表元对象。p代表代理对象
let person = {
    name: '张三',
    age: 18
}

// 模拟vue2实现响应式
//#region
// const p = {}; 
// Object.keys(person).forEach(item => {
//     Object.defineProperty(p, item, {
//         configurable: true, // true时使用delete才能删除对象的属性
//         get() {
//             return person[item]
//         },
//         set(value) {
//             person[item] = value;
//         }
//     })
// })
//#endregion

// 模拟vue3实现响应式
const p = new Proxy(person, {
    // 有人读取p的某个属性时调用
    get(target, propName) {
        // return target[propName]

        // vue3使用的是Reflect,因为使用这个如果报错的话也不会导致代码执行不下去
        return Reflect.get(target, propName)
    },
    // 有人修改p的某个属性,或给p追加某个属性时调用
    set(target, propName, value) {
        // target[propName] = value;

        // vue3使用的是Reflect,因为使用这个如果报错的话也不会导致代码执行不下去
        Reflect.set(target, propName, value)
    },
    // 有人删除p的某个属性时调用
    deleteProperty(target, propName) {
        // return delete target[propName]

        // vue3使用的是Reflect,因为使用这个如果报错的话也不会导致代码执行不下去
        return Reflect.deleteProperty(target, propName)
    }
})

文章来源:https://blog.csdn.net/weixin_50236973/article/details/134949927
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。