大年初五迎财神啦,祝大家五方财神进门来💰💰💰💰💰💰💰💰,好运连连吖~❤️❤️❤️❤️❤️❤️❤️
🌬🌬🌬前言:今天来分享一下老生常谈系列之响应式,不管在日常工作应用中,还是在面试的时候经常会谈到响应式的问题,以下是我对响应式的一些浅浅的理解,大家有补充的或者不同的见解欢迎在评论区留言哈📝📝📝
上才艺🥁🥁🥁🥁🥁🥁
📢📢📢 剧情:某某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变化时,就会触发更新函数,方便快捷。
- 缺点:不能检测数组和对象的变化,具体详见,只有被监听 的指定属性,才可以触发
getter
和setter
,在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
得到一个新的对象(代理对象),同时拥有被代理对象中所有的属性,修改对象的指定属性时,我们应该对 代理对象 进行修改,并且代理对象的任何一个属性都可以触发handler
的getter
和setter
。 - 缺点:兼容问题,在IE11以下的浏览器都不兼容。