vue2中的数据劫持和vue3中的数据劫持的区别?

183 阅读3分钟

前言

Vue3发布已经有一段时间了,今天来整理一下这两个版本有什么区别,熟悉之后可以帮助我们更好的理解和上手Vue3;

一、双向数据绑定的原理

Vue2实现数据双向绑定的原理是利用ES5的一个API Object.definePropert() 对数据进行劫持,结合发布订阅模式的方式来实现的。而在Vue3中使用了ES6的Proxy API对数据代理。

我们可以思考两个问题: 1.为什么Vue3使用了Proxy?2.有什么优势?

回答这两个问题之前我们先想想Vue2版本使用Object.definePropert()方法有什么缺陷: 对象不能监听到的情况: 对象属性的新增和删除。 不过vue给我们提供了解决的方案,使用 vue.set(obj,newKey,newValue)方法新增属性,使用 Vue.delete(obj, key) 去删除属性。 数组不能监听到的情况: 1.直接通过下标赋值 arr[i] = value 2. 直接修改数组的长度 尤大大解答过这个问题,其实并不是技术层面做不到,而是因为通过object.defineProperty方法对每一个数据进行监听性能代价太大,收获和付出不成正比。

回答上边的问题之前,我们先来看看proxy的用法:

语法:const p = new Proxy(target, handler)

参数: target: 要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理) handler: 一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。 通过Proxy,我们可以对设置代理的对象上的一些操作进行拦截,外界对这个对象的各种操作,都要先通过这层拦截。(和defineProperty差不多) 举例子:

//定义一个需要代理的对象
let person = {
   
    age: 0,
    school: '西电'
}
//定义handler对象
let hander = {
    get(obj, key) {
        // 如果对象里有这个属性,就返回属性值,如果没有,就返回默认值66
        return key in obj ? obj[key] : 66
    },
    set(obj, key, val) {
        obj[key] = val
        return true
    }
}
//把handler对象传入Proxy
let proxyObj = new Proxy(person, hander)

// 测试get能否拦截成功
console.log(proxyObj.age)//输出0
console.log(proxyObj.school)//输出西电
console.log(proxyObj.name)//输出默认值66

// 测试set能否拦截成功
proxyObj.age = 18
console.log(proxyObj.age)//输出18 修改成功

结论:可以看出,Proxy代理的是整个对象,而不是对象的某个特定属性,不需要我们通过遍历来逐个进行数据绑定。

注意: 之前我们在使用Object.defineProperty()给对象添加一个属性之后,我们对对象属性的读写操作仍然在对象本身。 但是一旦使用Proxy,如果想要读写操作生效,我们就要对Proxy的实例对象proxyObj进行操作。

看到这里你应该就明白了Vue3版本使用Proxy的优势了,它可以轻松解决Vue2版本中出现的问题: 1.一次只能对一个属性进行监听,需要遍历来对所有属性监听。 2. 在遇到一个对象的属性还是一个对象的情况下,需要递归监听。 3. 对于对象的新增属性,需要手动监听 4. 对于数组通过push、unshift方法增加的元素,也无法监听

而且Proxy支持13种拦截操作,