vue中的watch与computed的区别

目录

一、计算属性(computed)

1、计算属性的特点

[2、计算属性的原理------getter 和 setter](#2、计算属性的原理——getter 和 setter)

[3、computed 里返回一个函数------给 computed 属性中的方法传参](#3、computed 里返回一个函数——给 computed 属性中的方法传参)

[4、computed 与 methods 的区别](#4、computed 与 methods 的区别)

二、侦听器(watch)

1、侦听器的特点

[2、使用 watch的注意事项](#2、使用 watch的注意事项)

3、watch的两个属性

(1)、deep

(2)、immediate

4、深度监听一个对象时如何避免新值与旧值相等呢?

[5、watch 与 $watch 的关系](#5、watch 与 $watch 的关系)

[6、watch 的使用案例](#6、watch 的使用案例)

[三、计算属性 和 侦听器 适用场景](#三、计算属性 和 侦听器 适用场景)

[四、推荐几篇关于 computed 和 watch 的原理的深度解析好文](#四、推荐几篇关于 computed 和 watch 的原理的深度解析好文)


一**、计算属性(computed)**

1、计算属性的特点

  • 支持 数据缓存------页面重新渲染时,只有数据发生了改变,才会执行相应的函数。
  • 减少模板中计算逻辑。
  • 依赖"响应式数据"。

2、计算属性的原理------getter 和 setter

在computed中的,属性都有一个get和一个set方法。当 computed 属性的属性值是函数,那么默认会走get方法,函数的返回值就是属性的值;当数据变化时,调用set方法。

计算属性默认只有 getter,在需要时你也可以提供一个 setter。

computed: {
  fullName: {
    // getter
    get: function () {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set: function (newValue) {
      var names = newValue.split(' ')
      this.firstName = names[0]
      this.lastName = names[names.length - 1]
    }
  }
}

再运行 vm.fullName = 'John Doe' 时,setter 会被调用,vm.firstNamevm.lastName 也会相应地被更新。

实战应用案例:用computed监听:在子组件中更新父组件中传过来的变量

3、computed 里返回一个函数------给 computed 属性中的方法传参

<template lang="pug">
  .topic-list(v-for='item in topicList')
    a(:href='splitUrl(item.id)' target='_blank') {
  
  {item.name}}
</template>
<script>
export default {
  computed: {
    splitUrl () {
      return id => `${window.location.origin}/list/topic/${id}${this.isFromYY ? `?yyId=${this.info.yyId}` : ''}`
    }
  }
}
</script>

使用了闭包。

4、computed 与 methods 的区别

<template>
    <div>
        <p>reverseMsg1:{
  
  {reverseMsg1}}</p>
        <p>reverseMsg2:{
  
  {reverseMsg2()}}</p>
        <button @click="()=> $forceUpdate()">强制更新</button>
        <div>
            <input type="text" v-model="msg">
        </div>
    </div>
</template>

<script>

export default {

data() {

return {

msg: "hello vue"

}

},

computed: {

reverseMsg1() {

console.log("reverseMsg1执行了");

return this.msg.split("").reverse().join("");

}

},

methods: {

reverseMsg2(){

console.log("reverseMsg2执行了");

return this.msg.split("").reverse().join("");

}

},

}

</script>

由上面这个例子可以看出:

computed 与 methods 的区别:

  • computed里定义的函数,函数名可以作为变量直接使用,默认 会执行该函数体。
  • methods里定义的函数,必须调用 才能执行该函数体。
  • computed里的数据会被缓存,每次更新都会先对比数据是否发生了变化,是才更新,否不执行,大大减少了渲染时间。
  • methods里的函数不会被缓存,只要数据有更新,就会执行对应的函数。
  • 如果你不希望有缓存,请用方法来替代。

二、侦听器(watch)

1、侦听器的特点

  • 支持异步
  • 可以侦听任何逻辑,比如:函数节流,Ajax异步获取的数据,甚至操作DOM(不建议)。
  • 页面重新渲染时,无论值变不变,都会重新执行,因为watch不支持数据缓存。
  • 监听的函数接收两个参数,第一个参数是:新值,第二个参数是:原来的值。

2、使用 watch的注意事项

不要在 watch 中使用箭头函数,因为箭头函数没有 this,它的 this 会继承它的父级函数,但是它的父级函数是 window,导致箭头函数的 this 指向 window,而不是 Vue 实例。

3、watch的两个属性

(1)、deep

默认情况下,侦听器只会监听数据本身的改变,若要进行深度监听,那就需要使用 deep。

deep:其值是 true 或 false。深度监听,用来控制是否要监听对象内布值的变化(在页面初始化化时不会触发,只有当值改变时才会触发)。

不过,deep 无法监听到数组的变动和对象的新增,参考 vue 数组变异,只有以响应式的方式触发才会被监听到------[vm.set](https://cn.vuejs.org/v2/api/#vm-set "vm.set")。

(2)、immediate

默认情况下,侦听器需要 data 后面值改变了才会生效,若需要侦听器一进入页面就生效,那就需要使用 immediate。

immediate:其值是 true 或 false。组件加载时,用来控制是否要立即执行回调函数(在页面初始化后是否立即执行)。

4、深度监听一个对象时如何避免新值与旧值相等呢?

深度监听一个对象时,要监测到对象的具体需要被监听的属性,就能够解决新值与旧值相等的问题。

例如:问题再现

data () {
  return {
    obj: { a: 1 }
  }
},
watch: {
  obj (newVal, oldVal) {
    console.log(newVal, oldVal)
  }
}

上述代码中,当改变 obj 里属性的值时,打印 newVal 和 oldVal 的结果,发现他们是相等的。这是因为:改变一个对象里属性的值时,新值和旧值指向的是同一块内存区,所以无法拿到旧值,也可以理解为是浅拷贝的问题。我们可以通过直接监听该对象里的属性来解决这个问题:

data () {
  return {
    obj: { a: 1 }
  }
},
watch: {
  "obj.a": (newVal, oldVal) => {
    console.log(newVal, oldVal)
  }
}

5、watch 与 $watch 的关系

Vue 实例将会在实例化时调用$watch(),遍历 watch 对象的每一个属性

6、watch 的使用案例

<template>
    <div>
        {
  
  {$data}}
        <br/>
        <button @click="() => {a += 1}">a+1</button>
    </div>
</template>

<script>

export default {

data() {

return {

a: 1,

b: {c: 2, d: 3},

e: {

f:{

g: 4

}

},

h: []

}

},

watch: {

a(val, oldVal){

this.b.c += 1;

console.log("new: %s, old: %s", val, oldVal);

},

"b.c": function(val, oldVal){

this.b.d += 1;

console.log("new: %s, old: %s", val, oldVal);

},

"b.d": function(val, oldVal){

this.e.f.g += 1;

console.log("new: %s, old: %s", val, oldVal);

},

e: {

handler: function(){

this.h.push("哈")

},

deep: true

},

h(val, oldVal){

console.log("new: %s, old: %s", val, oldVal);

}

},

}

</script>

三、计算属性 和 侦听器 适用场景

computed 能做的,watch 都能做,反之不行。不过,能用 computed 的尽量用 computed。

如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个 多对一 或者 一对一,一般用computed。

比如:

<template>
    <div>
        {
  
  {fullName}}
        <div>firstName:<input type="text" v-model="firstName"></div>
        <div>lastName:<input type="text" v-model="lastName"></div>
    </div>
</template>

<script>

export default {

/**

* 用计算属性去实现

*/

data() {

return {

firstName: "charles",

lastName: "jake",

}

},

computed: {

fullName(){

return this.firstName + " " + this.lastName;

}

},

/**
 * 用侦听器去实现
 */
// data() {
//     return {
//         fullName: &#34;charles jake&#34;,
//         firstName: &#34;charles&#34;,
//         lastName: &#34;jake&#34;,
//     }
// },
// watch: {
//     firstName(val, oldVal){
//         if(val !&#61; oldVal){
//             this.fullName &#61; val &#43; &#34; &#34; &#43; this.lastName;
//         }
//     },
//     lastName(val, oldVal){
//         if(val !&#61; oldVal){
//             this.fullName &#61; this.firstName &#43; &#34; &#34; &#43; val;
//         }
//     }
// },

}

</script>

四、推荐几篇关于 computed 和 watch 的原理的深度解析好文

深入理解 Vue Computed 计算属性:https://segmentfault.com/a/1190000010408657

Vue的数据依赖实现原理简析:https://segmentfault.com/a/1190000010014281#articleHeader2

vue中watch源码阅读笔记:[vue中watch源码阅读笔记 - Clarence2J - 博客园](https://www.cnblogs.com/Clarence2J/p/6860329.html "vue中$watch源码阅读笔记 - Clarence2J - 博客园")

相关推荐
万叶学编程1 小时前
Day02-JavaScript-Vue
前端·javascript·vue.js
前端李易安3 小时前
Web常见的攻击方式及防御方法
前端
PythonFun3 小时前
Python技巧:如何避免数据输入类型错误
前端·python
知否技术3 小时前
为什么nodejs成为后端开发者的新宠?
前端·后端·node.js
hakesashou3 小时前
python交互式命令时如何清除
java·前端·python
天涯学馆3 小时前
Next.js与NextAuth:身份验证实践
前端·javascript·next.js
HEX9CF4 小时前
【CTF Web】Pikachu xss之href输出 Writeup(GET请求+反射型XSS+javascript:伪协议绕过)
开发语言·前端·javascript·安全·网络安全·ecmascript·xss
ConardLi4 小时前
Chrome:新的滚动捕捉事件助你实现更丝滑的动画效果!
前端·javascript·浏览器
ConardLi4 小时前
安全赋值运算符,新的 JavaScript 提案让你告别 trycatch !
前端·javascript