面试常见题:Watch与computed的区别

126 阅读2分钟

官网文档中的解释:

Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性。当你有一些数据需要随着其它数据变动而变动时,你很容易滥用 watch——特别是如果你之前使用过 AngularJS。然而,通常更好的做法是使用计算属性而不是命令式的 watch 回调。
看以下例子:

<div id="demo">{{ fullName }}</div>
    var vm = new Vue({
      el: '#demo',
      data: {
        firstName: 'Foo',
        lastName: 'Bar',
        fullName: 'Foo Bar'
      },
      watch: {
        firstName: function (val) {
          this.fullName = val + ' ' + this.lastName
        },
        lastName: function (val) {
          this.fullName = this.firstName + ' ' + val
        }
      }
    })

当姓或名改变时,调用firstNamelastName方法,最终目的都是改变fullName中的值,而且fullName中的值是依赖于firstNamelastName这两个变量的,如果我们使用computed方法那就不需要写两个方法来对数据进行监听,如下:

    var vm = new Vue({
      el: '#demo',
      data: {
        firstName: 'Foo',
        lastName: 'Bar'
      },
      computed: {
        fullName: function () {
          return this.firstName + ' ' + this.lastName
        }
      }
    })

这样子的效果是一样的,并且减少了代码量。
那么这两者的区别在哪里呢?
比如现在有这么一个需求,当姓名更新时,延迟一秒再更新全名fullName中的数据,当我们使用computed的时候:

<!DOCTYPE html>
<html lang="en">
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<head>
</head>

<body>
  <div id="demo">
    姓:<input type="text" v-model="firstName" />
    名:<input type="text" v-model="lastName" />
    <div>全名:{{ fullName }}</div>
  </div>
  <script>
    var vm = new Vue({
      el: '#demo',
      data: {
        firstName: 'Foo',
        lastName: 'Bar'
      },
      computed: {
        fullName: function () {
          setTimeout(() => {
            return this.firstName + ' ' + this.lastName
          }, 1000)
        }
      }
    })
  </script>
</body>

显然我们是无法在computed中做一些异步操作的。
我们可以使用watch方法实现:

  <div id="demo">
    姓:<input type="text" v-model="firstName" />
    名:<input type="text" v-model="lastName" />
    <div>全名:{{ fullName }}</div>
  </div>
  <script>
    var vm = new Vue({
      el: '#demo',
      data: {
        firstName: 'Foo',
        lastName: 'Bar',
        fullName:'Foo Bar'
      },
      watch:{
        firstName(val){
          setTimeout(()=>{
            this.fullName = val + this.lastName
          },1000)
        },
        lastName(val){
          setTimeout(()=>{
            this.fullName = this.firstName + val
          },1000)
        }
      }
    })
  </script>

总结

共同点:

  • 都可以用来对数据进行监听 不同点:
  • computed能做到的,watch都能做到,但是watch能做到的computed不一定都能做到
  • 当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作 ( 访问一个 API,防抖节流 ),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。
  • 当我们的数据依赖于现有数据的时候应该使用computed,因为computed的特性可以缓存数据,避免每次都需要重新计算.