• Vue2和Vue3响应式区别和理解


    一、Vue2响应式

    vue2响应式:核心代码是使用Object.defineProperty()来劫持对象中每一个属性的set和get方法。

    先来说说Object.defineProperty,称之为对象的属性描述符,可以设置对象的属性是否可以删除(Configurable)、是否可以枚举(Enumerable)、是否可以修改(Writable)、返回值(value)、set(重要,修改触发的回调函数)、get(重要,获取触发的回调函数)

    举例子:

    var obj = {
         name: '小明',
         age: 18
       }
    
       Object.defineProperty(obj, "name", {
          set(newValue) {
           console.log('调用set方法', newValue);
           name = newValue
          },
          get() {
            console.log('调用get方法');
            return name
          }
       })
    
       Object.defineProperty(obj, "age", {
          configurable: false,
          enumerable: true
       })
    
       // 调用set
       obj.name = 123
       // 调用get
       console.log(obj.name)
       // 尝试删除age
       delete obj.age
       console.log(obj.age);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    这是Object.defineProperty的基本用法,也是Vue2的响应式核心,但是,这么做是有缺点的。

    缺点一:如果对象中属性过多,那么需要给每个属性都绑定defineProperty,十分损耗效率。

    缺点二:只能监听对象属性的修改、读取,如果涉及删除、增加就无法响应式刷新页面了(只能通过Vue.set)

       this.$set(this.obj, key, value)
       Vue.set(this.obj, key, value)
        
       this.$delete(this.obj, key)
       Vue.delete(this.obj, key)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    缺点三:通过下标、length修改数组也不会响应式刷新页面,可以直接重新赋值,或者使用filter、map、concat、slice等生成新数组对其赋值

       this.$set(this.arr, index, value)
       Vue.set(this.arr, index, value)
        
       this.$delete(this.arr, index)
       Vue.delete(this.arr, index)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    还可以使用操作数组的函数

    splice(),push(), pop(), shift(), unshift(), sort(), reverse()
    
    • 1

    好了,缺点就这些,下面我们来浅聊一下Vue2响应式是如何实现的。

    顺序是:数据劫持(数据代理)-> 依赖收集 -> 订阅发布

    首先observe函数会将传入的数据进行递归处理成一个个值,然后给他们每个都重写get和set方法。

    然后Dep类作为收集者,需要保存收集到的依赖,在observe函数执行同时创建Dep实例,也就是每个属性对应一个Dep实例,在Vue解析到模板中的{{}}时,会创建Watcher实例,也就是观察者,可以收集数据的所有依赖,通过调用dep.depend,存放到对应Dep实例的sub数组中。

    最后当数据发生变化,就会触发Dep类中的dep.notify方法,通知所有依赖进行更新。

    二、Vue3响应式

    和Vue2不同的是,它的核心是es6的Proxy结合Reflect实现的,使用代理,可以不直接操作对象,这样就可以监听到所有对象的增删改查,同时也提升了效率。

    还是先看看核心Proxy:

    es6新增了Proxy类,顾名思义,就是代理的作用。如果我们想监听一个对象,就可以先创建代理对象,之后对对象的所有操作,都由代理对象完成,可以监听我们的所有操作。

    Reflect是es6新增的另一个API,是一个对象,顾名思义是反射。提供了很多操作Object的方法,增加Reflect的原因是最开始ECMA设计时,没有考虑到未来会给Object设置很多方法,造成臃肿的现象,而且有些操作放到object里面并不合适,所以新增了这个API。另外在使用Proxy时,可以做到不操作原对象

    二者结合:

      var obj = {
                name: 'xiaoming',
                age: 18
            }
            // 结合好处一:不再直接操作对象
            // 结合好处二:返回一个Boolean类型,可以进行判断
            var objProxy = new Proxy(obj, {
                set: function(target, key, newValue) {
                    const isSuccess = Reflect.set(target,key,newValue)
                    if(!isSuccess){
                        throw new Error(`set ${key} failure`)
                    }
                }
            })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    Vue3的响应式是将Vue2的Object.defineProperty替换成new Proxy+Reflect,其他思想大致是一样的。

  • 相关阅读:
    2023山东老博会·CSOLDE中国国际养老服务业展览会
    【专项测试系列】-缓存击穿、穿透、雪崩专项测试
    java毕业设计奖助学金评审(附源码、数据库)
    HCIP 实验作业(ppp实验)
    轻松查找,一键打印:手把手教你做记账明细管理
    【BOOST C++ 11 时钟数据】(1)计时码表(11-13)
    初识C++(三)
    【ENOVIA的使用】CESA空客集团数据统一管理案例
    视觉slam十四讲CH5 ---相机与图像
    Linux入门教程:P15->软件包管理
  • 原文地址:https://blog.csdn.net/q879936814/article/details/126372668