Vue3数据响应式原理

140 阅读2分钟

一、回顾Vue2

1、Vue2中的响应式原理

  • 对象类型:通过Object.defineProperty()对属性的读取丶修改进行拦截(数据劫持)
  • 数组类型:通过重写更新数组的一系列方法来实现拦截。
let person = {
            name:'蔡徐坤',
            age:18
        }

let p = {}
Object.defineProperty(p, "name", {
    get(){      //有人读取name时调用
        return person.name;
    },
    set(value){      //有人修改name时调用
        console.log("有人修改了name属性")
        person.name = value
    }
});

Object.defineProperty(p, "age", {
    get(){      //有人读取age时调用
        return person.age;
    },
    set(value){      //有人修改age时调用
        console.log("有人修改了age属性")
        person.age = value
    }
});

此时,p对象就完成了对person对象的代理,当读取p.name时,实际上是在读取person.name,当修改p.name时,实际上person中name属性的值也会随之更新。

2、vue2的响应式的一些问题

1.新增属性,或者删除属性,界面不会更新(解决方法:利用setset、delete)

2.直接通过下标修改数组,界面不会自动更新(解决方法:利用$set、splice())

二、Vue3中的响应式原理

1、原理

  • 通过Proxy(代理):拦截对象中任意属性的变化,包括属性的读写,属性的添加,属性的删除等。
  • 通过Reflect(反射):对源对象的属性进行操作
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
 
</body>
<script>
    //源数据
    let obj = {
        name:'蔡徐坤',
        age:18
    }
 
    // 模拟vue3中的响应式
    //Proxy第一个参数是源数据。第二个参数是配置
    const p = new Proxy(obj,{
        // 读取
        get(target,propName){
            console.log(`读取了p的${propName}属性`)
            //反射
            return Reflect.get(target,propName)
        },
        // 修改,新增
        set(target,propName,value){
            console.log(`修改了p的${propName}属性,准备更新界面`)
            return Reflect.set(target,propName,value)
        },
        //删除
        deleteProperty(target,propName){
            console.log(`删除了p的${propName}属性,准备更新界面`)
            return Reflect.deleteProperty(target,propName)
        }
    })
</script>
</html>

2、proxy(代理)

Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。

被 Proxy 代理虚拟化的对象。它常被作为代理的存储后端。根据目标验证关于对象不可扩展性或不可配置属性的不变量(保持不变的语义)。

Proxy第一个参数是源数据。第二个参数是配置

3、Reffect(反射)

定义一个对象obj,obj下面有a,两个属性。一般我们要读取a属性,会用obj.a来实现。其实还有另外一种方式。就是Reflect。Reflect.get(obj,'a')

Reflect是一个组合的对象,它提供了阻止 JavaScript 操作的方法。Reflect不是一个函数对象,因此它是不可构造的。

在reffect身上,就有defineProperty()这个方法

3、参数

target:
要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。

handler:
一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。

三、总结

在Vue2中,数据响应式主要借助Object.defineProperty()来实现,存在的缺陷是无法操作数据的增加和删除;

在Vue3中,数据响应式主要借助proxyReffect配合实现,可以做到实现数据的增删改查。