首页 > 代码库 > ch-4 计算属性

ch-4 计算属性

1 计算属性
1.1 模板内的表达式是非常便利的,但是它们实际上只用于简单的运算。
在模板中放入太多的逻辑会让模板过重且难以维护。

<div id="test1">
           {{str.split(‘‘).reverse().join(‘‘)}}
</div>

      <script>
            let app1 = new Vue({
                 el: ‘#test1‘,
                 data: {
                     str: ‘hello world‘
                 }
            });
      </script>

这种写法的弊端:
在这种情况下,模板不再简单和清晰。在意识到这是反向显示 str 之前,
你不得不再次确认第二遍。当你想要在模板中多次反向显示 str 的时候,
问题会变得更糟糕。

这就是对于任何复杂逻辑,你都应当使用计算属性的原因。

1.2 基本计算属性
<div id="test2">
                <p>原始的效果:{{str}}</p>
                <p>反转后的效果:"{{reverse}}"</p>
</div>

        <script>
            let app2 = new Vue({
                       el: ‘#test2‘,
                       data: {
                           str: ‘hello world‘
                       },
                       computed: {
                           //computed的getter
                           reverse: function () {
                                return this.str.split(‘‘).reverse().join(‘‘);
                           }
                       }
            });
        </script>
        这里声明了一个计算属性 reverse。
提供的函数将用作属性 vm.reverse 的 getter 。

可以打开浏览器的控制台,自行修改例子中的 app2 。 
app2.reverse 的值始终取决于 app2.str 的值。
可以像绑定普通属性一样在模板中绑定计算属性。
Vue 知道 app2.reverse 依赖于 app2.str ,因此当 app2.str 发生改变时,所有依赖于 app2.reverse 的绑定也会更新。
而且最妙的是我们已经以声明的方式创建了这种依赖关系:计算属性的 getter 是没有副作用,这使得它易于测试和推理。

技术分享

1.3 计算缓存(计算属性) vs Methods 可以通过调用表达式中的 method 来达到同样的效果
<div id="test2">
            <p>原始的效果:{{str}}</p>
            <p>反转后的效果:"{{reverse}}"</p>
            <p>反转后的效果:"{{reverseMe()}}"</p>
    </div>

    <script>
      let app2 = new Vue({
                 el: ‘#test2‘,
                 data: {
                     str: ‘hello world‘
                 },
                 computed: {
                      reverse: function () {
                          return this.str.split(‘‘).reverse().join(‘‘);
                      }
                  },
                  methods: {
                      reverseMe: function () {
                          return this.str.split(‘‘).reverse().join(‘‘);
                      }
                  }
       });
    </script>

技术分享

我们可以将同一函数定义为一个 method 而不是一个计算属性。对于最终的结果,两种方式确实是相同的。
然而,不同的是计算属性是基于它们的依赖进行缓存的
计算属性只有在它的相关依赖发生改变时才会重新求值
这就意味着只要 str 还没有发生改变,多次访问 reverse 计算属性会立即返回之前的计算结果,而不必再次执行函数。

相比而言,只要发生重新渲染,method 调用总会执行该函数。
我们为什么需要缓存?假设我们有一个性能开销比较大的的计算属性 A ,它需要遍历一个极大的数组和做大量的计算。
然后我们可能有其他的计算属性依赖于 A 。
如果没有缓存,我们将不可避免的多次执行 A 的 getter!
如果你不希望有缓存,请用 method 替代。

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

比较例子:
<div id="test4">{{fullName}}</div>
  <div id="test5">{{fullName}}</div>

  <script>
      let app4 = new Vue({
          el: ‘#test4‘,
          data: {
              firstName: ‘Jeson‘,
              lastName: ‘hu‘,
              fullName: ‘Jesonhu‘
          },
          watch: {
              firstName: function (val) {
                  this.fullName = val +‘ ‘+ this.lastName;
              },
              lastName: function (val) {
                  this.fullName = this.firstName +‘ ‘+ val;
              }
          }
      });
      
      let app5 = new Vue({
         el: ‘#test5‘,
         data: {
             firstName: ‘Jeson‘,
             lastName: ‘hu‘
         },
         computed: {
             fullName: function () {
                  return this.firstName +‘ ‘+ this.lastName;
             }
         }
      });
  </script>
1.5 计算 setter
计算属性默认只有 getter ,不过在需要时你也可以提供一个 setter
<div id="test6">{{fullName}}</div>

    <script>
      let app6 = new Vue({
              el: ‘#test6‘,
              data: {
                  firstName: ‘Jeson‘,
                  lastName: ‘hu‘
              },
              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]
                      }
                  }
              }
          });
    </script>
    现在在运行 app6.fullName = ‘John Doe‘ 时, setter 会被调用,
app6.firstName 和 app6.lastName 也相应地会被更新。

2 观察 Watchers
虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的 watcher 。
这是为什么 Vue 提供一个更通用的方法通过 watch 选项,来响应数据的变化。
当你想要在数据变化响应时,执行异步操作或开销较大的操作,这是很有用的。

ch-4 计算属性