Vue专题 02_计算属性(computed) VS 方法(methods)

2022-09-26 11:34:26 浏览数 (1)

先来看看用计算属性方法来实现同一效果:

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>watch和computed(computed实现)</title>
    <script src="./js/vue.js"></script>
  </head>
  <body>
    <div id="root">
      <p v-html="html"></p>
      姓:<input type="text" v-model="firstName" /><br />
      名:<input type="text" v-model="lastName" /><br />
      姓名:
      <h4>计算属性实现</h4>
      <h3>{{fullName}}</h3>
      <h4>方法实现</h4>
      <h3>{{getFullName()}}</h3>
    </div>
    <script>
      const vm = new Vue({
        el: '#root',
        data: {
          firstName: '张',
          lastName: '三',
        },
        computed: {
          fullName() {
            return this.firstName   '-'   this.lastName;
          },
        },
        methods: {
          getFullName() {
            return this.firstName   '-'   this.lastName;
          },
        },
      });
    </script>
  </body>
</html>

两种方式的最终结果都是完全相同的(这里解释一下为什么会相同:当计算属性所依赖的数据发生改变时,计算属性会重新调用;当data中的任何一个数据发生变化时,Vue的模板都会重新解析一遍(Vue都会拿过来模板整体再阅读一遍),所以方法也被调用了一次)

看起来用计算属性和方法好像都可以,其实它们两个有着本质的区别:

主要区别:

1. 调用方式不同

(以上边代码为例)

  • computed在HTML中的插值语法:{{fullName}} computed定义的方法是以属性的形式访问的,和data中的属性访问形式一样
  • methods在HTML中的插值语法:{{getFullName()}} methods定义的方法,必须加上()来调用,否则会出现如下情况:

2. 是否有缓存

computed是有缓存机制的,而methods没有

验证:

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
 <head>
   <meta charset="UTF-8" />
   <meta http-equiv="X-UA-Compatible" content="IE=edge" />
   <meta name="viewport" content="width=device-width, initial-scale=1.0" />
   <title>watch和computed(computed实现)</title>
   <script src="./js/vue.js"></script>
 </head>
 <body>
   <div id="root">
    姓:<input type="text" v-model="firstName" /><br />
    名:<input type="text" v-model="lastName" /><br />
    姓名:
     <h4>计算属性实现:</h4>
     <h3>①{{fullName}}</h3>
     <h3>②{{fullName}}</h3>
     <h3>③{{fullName}}</h3>
     <h3>④{{fullName}}</h3>
     <h3>⑤{{fullName}}</h3>
     <h4>方法实现:</h4>
     <h3>⑥{{getFullName()}}</h3>
     <h3>⑦{{getFullName()}}</h3>
     <h3>⑧{{getFullName()}}</h3>
     <h3>⑨{{getFullName()}}</h3>
     <h3>⑩{{getFullName()}}</h3>
     <hr>
    测试计算属性和方法的调用机制:
     <h1>{{test}}</h1>
   </div>
   <script>
     const vm = new Vue({
       el: '#root',
       data: {
         firstName: '张',
         lastName: '三',
         test: 0,
      },
       computed: {
         fullName() {
           console.log('computed');
           return this.firstName   '-'   this.lastName;
        },
      },
       methods: {
         getFullName() {
           console.log('methods');
           
           return this.firstName   '-'   this.lastName;
        },
      },
    });
</script>
 </body>
</html>

可以看到,刷新页面,初始打印一个computed,五个methods。

这说明计算属性调用了缓存机制,只打印了一次,后边的四次{{fullName}}并没有被调用(因为后四次直接获取了第一次缓存下来的值,计算属性会立即返回之前的计算结果,而不必再次执行函数。),试想一下,如果我再html中写的不是5次<h3>{{fullName}}</h3>,而是10000次甚至100000000次,如果没有缓存机制,他会执行100000000次,而有了缓存机制,它只用执行一次,后边不管多少次,直接拿第一次缓存的值即可,这大大节省了运算时间(尤其是要多次计算一个很复杂的属性的时候);方法被调用了五次,因为方法没有缓存机制,写了几次调用,函数就执行几次。

缓存机制的另外一个好处就是,当你修改计算属性所依赖的数据时,计算属性同样只会执行一次,后边任意多少次只需要拿第一次缓存下来的值即可;而方法的话,修改任意data中的值,html中写了多少次调用,就会调用多少次,这也可以从我修改firstName的值的时候,只打印一次computed,打印五次methods来验证。

3. 调用的时机不同

计算属性:只有当你修改计算属性所依赖的数据时,才会被调用(如上GIF,当我修改test的值时,计算属性没有被调用,修改firstName时才会被调用)。比如:

代码语言:javascript复制
computed: {
  fullName: function () {
    return Date.now()
  }
}

如果计算属性改成这个,那么便不会再执行,因为Date.now()不是响应式依赖。

方法:当data中的任何一个数据发生变化时,Vue的模板都会重新解析一遍(Vue都会拿过来模板整体再阅读一遍),同时方法也会被调用(如上GIF,当我修改test和firstName的值时,方法都会被调用)。

4. 是否可以传参

计算属性不可以传参,而方法可以传参。

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
 <head>
   <meta charset="UTF-8" />
   <meta http-equiv="X-UA-Compatible" content="IE=edge" />
   <meta name="viewport" content="width=device-width, initial-scale=1.0" />
   <title>test3</title>
   <script src="../js/vue.js"></script>
 </head>
 <body>
   <div id="root">
     <!-- 计算属性不能传参: -->
     <h1>{{fullName}}</h1>
     <!-- 方法可以传参: -->
     <h1>{{getName('大潘')}}</h1>
   </div>
   <script>
     Vue.config.productionTip = false;
     const vm = new Vue({
       el: '#root',
       data: {
         eName: 'Dapan',
         cName: '潘潘',
      },
       computed: {
         fullName() {
           return this.eName   '-'   this.cName;
        },
      },
       methods: {
         getName(name) { //接收传过来的参数:'大潘'
           return this.eName   '-'   name;
        },
      },
    });
</script>
 </body>
</html>

其他说明

computed和methods不可以重名,Vue会把 methodsdata 里的东西,全部代理到Vue生成的对象中,这会将computed中重名属性覆盖。

计算属性的简写形式:

代码语言:javascript复制
computed: {
  fullName() {
    return this.eName   '-'   this.cName;
  },
},

而计算属性的一般形式:

代码语言:javascript复制
fullName: {
  get() {
    return this.eName   '-'   this.cName;
  },
  set(val) {
    // 代码
  },
},

在计算属性中传入的是一个属性,而在这个属性又有两个方法(getter和setter)。在读取数据时Vue自动调用getter,在设置值时使用setter,所以我们现在能够理解,为什么使用计算属性时不需要像调用方法时在后面跟上小括号,因为我们确实只是在使用属性而已。

关注公众号:学编程的GISer,获取更多干货知识!

0 人点赞