Skip to content

watch一个对象,新值与旧值相等的问题与解决 #3

@jiefancis

Description

@jiefancis
  • watch对象新值与久值相等
    vue中想要监听一个属性或者对象的变化进而执行某些操作时,可以使用watch侦听;如果想要深度监听对象中任意属性的变动,可以添加deep=true的配置;但是如果要对监听对象的新值与旧值的属性进行比对时,在控制台打印会发现监听对象的新值与久值一样,为了了解为什么以及怎么解决这问题,我又去看了vue的官方文档,发现vue的官方解释是在变更 (不是替换) 对象或数组时,旧值将与新值相同,因为它们的引用指向同一个对象/数组。Vue 不会保留变更之前值的副本。。此时就令人懵逼了,那有没有别的方法让我既能监听对象又能够使得拿到的新值与旧值不一样呢?答案是有的。

  • vm.$watch
    上面的问题,可能大部分人会想:可以单独监听对象中的属性,这个也是可以的,如果要监听对象中多个属性是需要写多个watch选项。那还有没有办法让我能够像watch一样传入deep=true就可以实现新值与久值不一样的结果呢?
    vue2源码watcher.js中,传入watch处理函数handler的oldValue是来源于getter的返回值;在watcher.js的实现中,getter可以是用户传入函数也可以是字符串,所以我们可以给$watch传入一个getter,使其返回当前对象未改动的值,使其一开始就保存到watch.value中,为避免对象引用共享的问题,我们需要返回对象的深拷贝;等待该对象属性值发生变动时,对象的更改不会影响到旧值。在线地址

  • ** $watch代码**

this.$watch(
   function() {
       return {
                ...JSON.parse(JSON.stringify(this.formData))
         }
   },
   function(newValue, oldValue) {},
  { deep: true}
)
  • watch的源码实现
// core/instance/state.js
Vue.prototype.$watch = function (expOrFn, cb, options) {
       const vm = this
       const watcher = new Watcher(vm, expOrFn, cb, options)
}

// core/instance/watcher
class Watcher {
     constructor( vm, expOrFn, cb, options) {
         this.getter = typeof expOrFn === 'function' ? expOrFn : parsePath(expOrFn)
         this.cb = cb
         this.immdiate = options.immdiate
         this.deep = options.deep
        
         // 旧值
        this.value = this.lazy ? undefined : this.get()
     }
     
      get () {
          // getter是我们传入的返回深拷贝对象的函数
           return this.getter(vm,vm)
      }
      run() {
           let value = this.get()
           let oldValue = this.value
           if(
                 value  !== oldValue ||
                 this.deep
             ) {
               this.cb(value, oldValue)
             }
      }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions