vue响应式原理——vue2和vue3的响应式实现区别

        Vue的核心功能点之一是响应式:Vue 会自动跟踪 JavaScript 状态并在其发生变化时响应式地更新 DOM。

        简单的来说就是,页面的渲染效果会随着数据变化而变化,不用我们去手动操作DOM树进行数据变化后的渲染。为了实现这一目的,我们最简单的实现思路就是去监听每一个对象中的值,在我们获取或者更新这个值是插上一脚来操作DOM,此时,就可以通过函数去操作这个对象,以达到我们的目的。

vue2的响应式实现方法:defineProperty

        Object.defineProperty() 是 JavaScript 中的一个方法,用于直接在一个对象上定义一个新属性,或者修改一个已经存在的属性。它提供了精细的控制能力,可以定义属性的特性(特性包括可枚举、可配置、可写性等),并可以定义 getter 和 setter,在属性被访问或者设置时执行自定义的行为。

        这里vue2的思路则为通过该方法来遍历对象,达到监听对象属性的目的,代码如下:

const obj = {
  a: 1,
  b: 2,
  c: {
    d: 3,
    e: 4,
  }
} as any

//观察
const observer = (obj: any) => {
  for (const key in obj) {
    let temp = obj[key]
    if (typeof obj[key] === 'object') {
      observer(obj[key])
    } else {
      Object.defineProperty(obj, key, {
        get() {
          console.log('读取', key)
          return temp
        },
        set(val) {
          console.log('修改', key)
          temp = val
        }
      })
    }
  }
}

observer(obj)

obj.a;// 读取 a
obj.b = 3; // 修改 b
obj.c.d; // 读取 c.d

obj.f = 5 // 新添属性 f 并修改 f

输出结果:

 

        这里我们可以发现, 我们用递归的方式来去对每个值进行了监听,但是对应后面新增的对象属性就没有相对性的监听效果,如果想进行监听,就需要对这个属性进行单独的处理:

const obj = {
  a: 1,
  b: 2,
  c: {
    d: 3,
    e: 4,
  }
} as any

//观察
const observer = (obj: any) => {
  for (const key in obj) {
    let temp = obj[key]
    if (typeof obj[key] === 'object') {
      observer(obj[key])
    } else {
      Object.defineProperty(obj, key, {
        get() {
          console.log('读取', key)
          return temp
        },
        set(val) {
          console.log('修改', key)
          temp = val
        }
      })
    }
  }
}

const set = (obj: any, key: string, value: any) => {
  obj[key] = value
  let temp = obj[key]
  if (typeof value === 'object') {
    observer(value)
  } else {
    Object.defineProperty(obj, key, {
      get() {
        console.log('读取', key)
        return temp
      },
      set(val) {
        console.log('修改', key)
        temp = val
      }
    })
  }
}

observer(obj)

obj.a;// 读取 a
obj.b = 3; // 修改 b
obj.c.d; // 读取 c.d

set(obj, 'f', {
  g: 5
}) // 修改 f

obj.f.g; // 读取 f

输出结果:

 vue3的响应式实现方法:Proxy

        Proxy 是 ES6 中新增的一个功能,它允许你在访问一个对象之前定义自定义行为。通过 Proxy,你可以创建一个代理对象来包裹目标对象,并可以拦截并重定义该对象的各种操作,如属性的读取、赋值、删除等操作,甚至可以自定义对象的行为。

       vue3使用的是Proxy来进行响应式操作的,这里就没必要将对象的所有属性进行遍历,而是使用哪个属性,则对哪个属性进行监听:

const obj ={
  a: 1,
  b: 2,
  c: {
    d: 3,
    e: 4,
  }
} as any

const option = {
  get(target: any, key: any) {
    console.log('读取', key)
    //判断是否是对象
    if (typeof target[key] === 'object') {
      return new Proxy(target[key], option)
    }
    return target[key]
  },
  set(target: any, key: any, value: any) {
    console.log('设置', key, value)
    //判断是否是对象
    if (typeof value === 'object') {
      target[key] = new Proxy(value, option)
      return true
    }
    return true
  },
}

const proxy = new Proxy(obj, option)

proxy.a = 10; // 设置 a 10
proxy.a; // 读取 a

proxy.c.f = 20; // 设置 c.f 20
proxy.c.f; // 读取 c.f

proxy.c; // 读取 c

输出结果:

总结

        vue2和vue3的响应式操作相比,vue2需要遍历对象,且对于新的属性无法直接进行监听,而vue3使用代理对象就不会出现这个问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星极天下第一

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值