Vue 中 computed 和 watch 的区别

computed 和 watch 的使用场景、特性对比及实现方式

问题

Vue 中 computed 和 watch 看似都能实现对数据的监听,它们有什么区别?

解答

computed 计算属性

计算属性基于 data 或 props 中的数据计算得到一个新值,这个新值只会根据依赖值的变化而变化。

data: {
    firstName: 'David',
    lastName: 'Beckham'
},
computed: {
    fullName: function() {
        return this.firstName + ' ' + this.lastName
    }
}

在模板中使用:

<p>姓名:{{ fullName }}</p>

注意:计算属性不能在 data 中定义,否则会报错。computed 属性如果是函数,默认走 get 方法,必须有返回值。

缓存特性

computed: {
    fullName: function () {
        console.log('computed') // 多次调用只打印一次
        return this.firstName + ' ' + this.lastName
    }
}

computed 只在初始化或依赖数据变化时执行,结果会被缓存。重复调用时,只要依赖数据不变,直接返回缓存结果。

getter/setter

computed: {
    fullName: {
        get() {
            return this.firstName + ' ' + this.lastName
        },
        set(val) {
            const names = val ? val.split(' ') : [];
            this.firstName = names[0]
            this.lastName = names[1]
        }
    }
}

watch 监听属性

watch 用于监听 Vue 实例上的属性变化,当属性变化时执行特定的业务逻辑。可以监听 data、props、computed 内的数据。

watch: {
    firstName: function(val) { 
        this.fullName = val + ' ' + this.lastName
    },
    lastName: function(val) {
        this.fullName = this.firstName + ' ' + val
    }    
}

监听函数有两个参数:第一个是新值,第二个是旧值。

深度监听

监听对象内部值的变化需要使用 deep 选项:

data: {
    fullName: {
        firstName: 'David',
        lastName: 'Beckham'
    }
},
watch: {
    fullName: {
        handler(newVal, oldVal) {
            console.log(newVal);
            console.log(oldVal);
        },
        deep: true
    }
}

深度监听可以监听到对象的变化,但 newVal 和 oldVal 会指向同一个对象,无法区分具体哪个属性变化。

监听对象的单个属性

方法一:直接监听属性

watch: {
    'fullName.firstName': function(newVal, oldVal) {
        console.log(newVal, oldVal);
    }
}

方法二:配合 computed 使用

computed: {
    firstNameChange() {
        return this.fullName.firstName
    }
},
watch: {
    firstNameChange() {
        console.log(this.fullName)
    }
}

应用场景

computed 适用于

  • 处理复杂的逻辑运算
  • 一个数据受一个或多个数据影响
  • 处理模板中的复杂表达式
  • 例如:购物车商品数量和总金额的关系

watch 适用于

  • 一个属性变化时需要执行特定业务逻辑
  • 数据变化时执行异步或开销较大的操作
  • 一个数据改变影响多个数据
  • 例如:监控路由变化、input 输入框的特殊处理

关键点

  • computed 有缓存机制,依赖数据不变时直接返回缓存结果;watch 不支持缓存,数据改变直接触发操作
  • computed 必须有返回值,返回值作为新的计算属性;watch 不需要返回值,主要执行业务逻辑
  • computed 不支持异步;watch 支持异步操作
  • computed 适合多对一的场景(多个数据影响一个结果);watch 适合一对多的场景(一个数据变化影响多个操作)
  • computed 基于依赖自动计算;watch 需要明确指定监听的数据源