在 Vue.js 中,我们可以通过 watch
对属性的变化进行监听。在使用 watch
时,可以通过设置 {deep: true}
进行深度监听,也可以省略这个参数从而进行浅度监听。但是,在实际使用时,往往会遇到深度监听和浅度监听的区别问题。
什么是深度监听和浅度监听
深度监听和浅度监听是针对 Vue.js 中 watch
对象的一个属性,可以通过设置 {deep: true}
对目标对象进行深度监听;对于省略 {deep: true}
,则进行浅度监听。下面,我们来看看两者的具体含义:
深度监听
当我们对一个复杂对象进行深度监听时,即便该对象的深层属性发生了改变,我们也会得到事件通知。
浅度监听
当我们对一个复杂对象进行浅度监听时,只有该对象本身引用的变化才会受到监听。
两者的执行时机
为了更好地理解区别,我们来看下两者的执行时机:
深度监听
- Vue.js 在检测到目标对象改变时,会递归遍历该对象的每一个属性,并对其进行监听。
浅度监听
- 每当我们修改了目标对象的属性时,Vue.js 监听到对象中某个属性的变化时,会将其放到一个“异步队列”中。所有的属性变化会在下一个事件循环周期中一次性处理。
如何正确地使用深度监听和浅度监听
两种监听方式各有优劣,我们在实际使用时需要根据具体情况做出选择。
深度监听
深度监听可以避免遗漏目标对象属性的变化,适用于需要监听目标对象中多个属性变化的情况,同时也可以对数组变化进行监听。
但是,在深度监听中会增加很大的开销,因为列队中的对象的属性都需要被递归遍历,所以对于性能要求较高的场合不建议使用深度监听。
浅度监听
浅度监听相对于深度监听而言,运行开销更小,在需要监听某个对象引用的变化时,我们可以使用浅度监听。同时在多个选项参数不同的情况下,浅度监听比深度监听良好地适用于经常使用 memoization 模式,而且还可以避免重复计算。
但是,utils.mergeOptions
这个方法中使用了 Vue.js 的内置函数 mergeField
,其浅度监听的处理方式往往会被我们忽略导致只有对象本身的变化被监听,有时会遗漏目标对象中某些属性的变化。
示例代码
-- -------------------- ---- ------- ------ ------- - ----- ---------------- ------ - ------ - -------- - -------- - ------- ---------- -- ---------- ------------- ---------- ------------ -- -------- - -------- - ------- ---------- -- ---------- ------------- ---------- ------------ -- -------- - -------- - ------- ---------- -- ---------- ------------- ---------- ------------ - - -- ------ - -------- - ------------ - -------------------- --------- ---- -- ----- ---- -- ------------ - -------------------- --------- ---- -- ------------ - -------------------- --------- ---- - -- --------- - --------------------------- - ------------- --------------------------- - ------------- ------------ - - -------- - ------- ------------- - - - -
在本示例中,我们分别对 object1
,object2
和 object3
进行了监听:
-- -------------------- ---- ------- -- - --------- ------ -------- - ------------ - -------------------- --------- ---- -- ----- ---- -- -- - --------- ---------- ------------ - --- - ---- ------------ - -------------------- --------- ---- -- -- - --------- ------ ------------ - -------------------- --------- ---- -
在 mounted
钩子函数中,我们尝试修改 object1
,object2
和 object3
中的属性,并观察在深度监听和浅度监听下的输出结果。
mounted() { this.object1.objProp.objKey = 'newObjValue' this.object2.objProp.objKey = 'newObjValue' this.object3 = { objProp: { objKey: 'newObjValue' } } }
- 修改
object1
中的属性时,由于它是深度监听,所以其内部属性的变化也被捕捉到了,成功打印了新值和旧值:
object1 changed { objProp: { objKey: 'newObjValue' }, testProp1: 'testValue1', testProp2: 'testValue2' }
- 修改
object2
中的属性时,由于它是浅度监听,所以只能获取到object2
自身的属性变化,内部属性的变化不会被捕捉:
object2 changed { objProp: { objKey: 'objValue' }, testProp1: 'testValue1', testProp2: 'testValue2' }
- 修改
object3
中的属性时,只有属性变化引用部分被捕获到:
object3 changed { objProp: { objKey: 'newObjValue' } }
总结
我们需要识别深度监听和浅度监听之间的区别,根据所处场景和需求合理选择两种监听方式。如果您需要高度精准的监听和处理,建议使用深度监听。如果您想在多个可变的参数之间快速切换,并优化计算结果,建议使用浅度监听。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/64fedad395b1f8cacdd8654f