老生常谈系列之关于响应式

41 阅读2分钟

恭喜发财吖.png

大年初五迎财神啦,祝大家五方财神进门来💰💰💰💰💰💰💰💰,好运连连吖~❤️❤️❤️❤️❤️❤️❤️

🌬🌬🌬前言:今天来分享一下老生常谈系列之响应式,不管在日常工作应用中,还是在面试的时候经常会谈到响应式的问题,以下是我对响应式的一些浅浅的理解,大家有补充的或者不同的见解欢迎在评论区留言哈📝📝📝

上才艺🥁🥁🥁🥁🥁🥁

📢📢📢 剧情:某某NPC发布了一个关于如何修复计算商品总价的漏洞任务,下面是部分任务内容🌝🌝🌝
// 现有一个有价格和数量属性的商品对象
let product = {
    price: 10,
    quantity: 2
}
// 计算一下总价
let total = 0
let effect = () => {
   total = product.price * product.quantity
}
effect()
console.log(`总价格:${total}`) // 第一次打印:20
// 修改商品数量
product.quantity = 5
console.log(`总价格:${total}`) // 打二次打印:?

🥸:某某职工小王修改商品数量后,口算一下得到的总价是10*5 = 50,但是实际程序计算出来的总价却是20,如果这段程序上线,可亏大了,必须尽快解决。

分析后我们了解到JS执行顺序是按照由上到下的顺序一行一行地执行,数量修改后,没有重新计算总价,那怎么才能让商品总价跟着变呢?
✍️✍️✍️解决方案:
1. 传统复制粘贴大法
// 第一次修改商品数量
product.quantity = 5
effect()
console.log(`总价格:${total}`) // 打二次打印:50

// 第二次修改商品数量
product.quantity = 10
effect()
console.log(`总价格:${total}`) // 打三次打印:100

...
  • 优点:动动手指,不用动脑。
  • 缺点:不够灵活。
2. Vue2的Object.defineProperty
// 现有一个有价格和数量属性的商品对象
let quantity = 2
let product = {
    price: 10,
    quantity: quantity
}

// 计算一下总价
let total = 0
let effect = () => {
   total = product.price * product.quantity
}
effect()
console.log(`总价格:${total}`)

Object.defineProperty(product, 'quantity', {
    // 监听 product.quantity = xx 的行为,在触发该行为时重新执行 effect
    set(newVal) {
      // 注意:这里不可以是 product.quantity = newVal,因为这样会重复触发 set 行为
      quantity = newVal
      // 重新触发 effect
      effect()
    },
    // 监听 product.quantity,在触发该行为时,以 quantity 变量的值作为 product.quantity 的属性值
    get() {
      return quantity
    }
  });

  • 优点:当quantity变化时,就会触发更新函数,方便快捷。
  • 缺点:不能检测数组和对象的变化,具体详见,只有被监听 的指定属性,才可以触发 gettersetter,在Vue中如果想要增加具备响应性的新属性,那么可以通过 Vue.set 方法实现。
3. vue3的响应性核心 API:proxy
// 现有一个有价格和数量属性的商品对象
let product = {
    price: 10,
    quantity: 2
}

// 计算一下总价
let total = 0
let effect = () => {
   total = proxyProduct.price * proxyProduct.quantity
}
effect()
console.log(`总价格:${total}`)

// new Proxy 接收两个参数(被代理对象,handler 对象)。
// product 被称为《被代理对象》,proxyProduct 被称为《代理对象》
const proxyProduct = new Proxy(product, {
  // 触发条件:proxyProduct.xx = xx 触发set
  // 四个参数:被代理对象 target,指定的属性名 key,新值 newVal,最初被调用的对象 receiver
  // 返回值: boolean 类型,true 表示属性设置成功
  set(target, key, newVal, receiver) {
      // 为 target 附新值
      target[key] = newVal
      // 触发 effect 重新计算
      effect()
      return true
  },
  // 触发条件:proxyProduct.xx 触发get
  // 三个参数: 被代理对象 tager,指定的属性名 key,最初被调用的对象 receiver
  // 返回值:proxyProduct.xx 的结果
  get(target, key, receiver) {
      return target[key]
  }

})
  • 优点:1. new Proxy 得到一个新的对象(代理对象),同时拥有被代理对象中所有的属性,修改对象的指定属性时,我们应该对 代理对象 进行修改,并且代理对象的任何一个属性都可以触发 handlergettersetter
  • 缺点:兼容问题,在IE11以下的浏览器都不兼容。

剧情未完待续,请听下回分解👀