vue中 computed 和 watch 的区别

321 阅读3分钟

computed

computed看上去是方法,但是实际上是计算属性,它会根据你所依赖的数据动态显示新的计算结果。计算结果会被缓存,computed的值在getter执行后是会缓存的,只有在它依赖的属性值改变之后,下一次获取computed的值时才会重新调用对应的getter来计算。

计算属性将被加入到 Vue 实例中。所有 getter 和 setter 的 this 上下文自动地绑定为 Vue 实例。 通过计算出来的属性不需要调用直接可以在 DOM 里使用。

一个简单例子:

var vm = new Vue({
  el: '#app',
  data: {
    message: 'hello'
  },
  template: `
  <div>
  <p>我是原始值: "{{ message }}"</p>
  <p>我是计算属性的值: "{{ computedMessage}}"</p> // computed 在 DOM 里直接使用不需要调用
  </div>
  `,
  computed: {
    // 计算属性的 getter
    computedMessage: function () {
      // `this` 指向 vm 实例
      return this.message.split('').reverse().join('')
    }
  }
})

如果不使用计算属性,那么 message.split('').reverse().join('') 就会直接写到 template 里,那么在模版中放入太多声明式的逻辑会让模板本身过重,尤其当在页面中使用大量复杂的逻辑表达式处理数据时,会对页面的可维护性造成很大的影响,computed 的设计初衷也正是用于解决此类问题。

而且计算属性如果依赖不变的话,它就会变成缓存,computed 的值就不会重新计算。

所以,如果数据要通过复杂逻辑来得出结果,那么就推荐使用计算属性。

使用场景:

适用于重新计算比较费时不用重复数据计算的环境。所有 getter 和 setter 的 this 上下文自动地绑定为 Vue 实例。如果一个数据依赖于其他数据,那么把这个数据设计为computed。

watch

watcher 则更像是一个 data 的数据监听回调,当依赖的 data 的数据变化,执行回调,在方法中会传入 newVal 和 oldVal。可以提供输入值无效,提供中间值 特场景。Vue 实例将会在实例化时调用 $watch(),遍历 watch 对象的每一个属性。如果你需要在某个数据变化时做一些事情,使用watch。

实例:

new Vue({
  data: {
    n: 0,
    obj: {
      a: "a"
    }
  },
  template: `
    <div>
      <button @click="n += 1">n+1</button>
      <button @click="obj.a += 'hi'">obj.a + 'hi'</button>
      <button @click="obj = {a:'a'}">obj = 新对象</button>
    </div>
  `,
  watch: {
    n() {
      console.log("n 变了");
    },
    obj:{
      handler: function (val, oldVal) { 
      console.log("obj 变了")
    },
      deep: true // 该属性设定在任何被侦听的对象的 property 改变时都要执行 handler 的回调,不论其被嵌套多深
    },
    "obj.a":{
      handler: function (val, oldVal) { 
      console.log("obj.a 变了")
    },
      immediate: true // 该属性设定该回调将会在侦听开始之后被立即调用
    }
  }
}).$mount("#app");

注意:不应该使用箭头函数来定义 watcher 函数,因为箭头函数没有 this,它的 this 会继承它的父级函数,但是它的父级函数是 window,导致箭头函数的 this 指向 window,而不是 Vue 实例

  • deep 控制是否要看这个对象里面的属性变化
  • immediate 控制是否在第一次渲染是执行这个函数

vm.$watch() 的用法和 watch 回调类似:

  • vm.$watch('data属性名', fn, {deep: .., immediate: ..})
vm.$watch("n", function(val, newVal){
      console.log("n 变了");
},{deep: true, immediate: true})

总结:

  • 功能上:computed是计算属性,也就是依赖其它的属性计算所得出最后的值。watch是去监听一个值的变化,然后执行相对应的函数。
  • 使用上:computed中的函数必须要用return返回;watch的回调里面会传入监听属性的新旧值,通过这两个值可以做一些特定的操作,不是必须要用return。
  • 性能上:computed中的函数所依赖的属性没有发生变化,那么调用当前的函数的时候会从缓存中读取,而watch在每次监听的值发生变化的时候都会执行回调。
  • 场景上:computed:当一个属性受多个属性影响的时候,例子:购物车商品结算;watch:当一条数据影响多条数据的时候,例子:搜索框。