Vue2和Vue3响应式区别

vue2:Object.defineProperty

最主要的两个属性,get和set

get

属性的getter属性,当模板使用变量时,就会触发这个函数,执行时不传入任何参数,此函数一般会返回自身的值

set

属性的setter函数,当属性值被改变时,会触发这个函数,执行时传入一个参数,也就是被赋予的新值,此函数一般会去间接的将最新的值更新给视图

实现响应式

 defineReactive(data, key, value) {
        // 一个 key 属性对应一个 Dep 对象
        Object.defineProperty(data, key, {
          enumerable: true,
          configurable: true,
          set(newValue) {
            // 如果值未变,就不操作
            if (newValue === value) {
              return
            }
            // 更改值
            value = newValue
            // 通知 watcher 更新值====== notify 内部调用 watcher 的 update 方法更新视图
            dep.notify()
          },
          get() {
            // 如果是视图层使用的数据触发 get 函数,就把对应的 watcher 添加到 dep 的 subs 中
            if (Dep.target) {
              dep.addSub(Dep.target)
            }
            return value
          },
        })
      }

Dep

 class Dep {
      constructor() {
        this.subs = []
      }
      // 添加 watcher 到 subs 中
      addSub(sub) {
        this.subs.push(sub)
      }
      // 调用 notify 函数通知 watcher =======通过 update 函数的调用通知
      notify() {
        this.subs.forEach(sub => {
          sub.update()
        })
      }
    }
    let dep = new Dep()

Watcher

 class Watcher {
      constructor(node, name, vm) {
        this.node = node
        this.name = name
        this.vm = vm
        // 
        Dep.target = this
        this.update()
        this.target = null
      }
      update() {
        this.node.nodeValue = this.vm[this.name]
      }
    }

缺点

  • 检测不到对象属性的添加和删除
  • 数组API方法无法监听到
  • 需要对每个属性进行遍历监听,如果嵌套对象,需要深层监听,造成性能问题

可以用$set方法解决添加失去响应式问题

正因为defineProperty自身的缺陷,导致Vue2在实现响应式过程需要实现其他的方法辅助(如重写数组方法、增加额外set、delete方法)

vue3:Proxy

它监听是针对一整个对象的,那么对这个对象的所有操作会进入监听操作,这就完全可以代理所有属性了

function reactive(obj) {
    if (typeof obj !== 'object' && obj != null) {
        return obj
    }
    // Proxy相当于在对象外层加拦截
    const observed = new Proxy(obj, {
        get(target, key, receiver) {
            const res = Reflect.get(target, key, receiver)
            return res
        },
        set(target, key, value, receiver) {
            const res = Reflect.set(target, key, value, receiver)
            return res
        },
        deleteProperty(target, key) {
            const res = Reflect.deleteProperty(target, key)
            return res
        }
    })
    return observed
}

Proxy有多达13种拦截方法,不限于apply、ownKeys、deleteProperty、has等等,这是Object.defineProperty不具备的

Proxy不兼容IE,defineProperty能支持到IE9

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值