---
# System prepended metadata

title: Vue.js 學習旅程Mile 11 – Computed 計算屬性篇
tags: [w3HexSchool, Javascript, Vue]

---

# Vue.js 學習旅程Mile 11 – Computed 計算屬性篇
###### tags: `w3HexSchool` `Vue` `Javascript`

## 基本用法
```htmlmixed=
<div id="example">
  <p>Original message: "{{ message }}"</p>
  <p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
```

```javascript=
var vm = new Vue({
  el: '#example',
  data: {
    message: 'Hello'
  },
  computed: {
    // a computed getter
    reversedMessage: function () {
      // `this` points to the vm instance
      return this.message.split('').reverse().join('')
    }
  }
})
```
computed 內的 reversedMessage function 就是一個 getter method，每當 message 的值有變化時，便重新計算把值存回 reversedMessage



## 計算屬性特性

### 具 function 運算能力 的 data 屬性
* 每個對應的計算屬性都是一個具有回傳值且沒有傳入參數的 function 。
* 在模板中直接以 function 名稱設置，不用加 ( )

### 跟著來源資料變化

* 這個來源資料之一必要是來自 Vue 實例內的 data，才能做響應式依賴。
* 資料變動時，掃 virtual DOM，看哪裡需要更動做修改。
* 沒有 DOM 就沒有 virtual DOM，有 DOM 資料才能做連動。

### 將結果暫存

* 有暫存機制(cache)，若來源資料沒有變化的話，便不會執行方法。

### getter ＆ setter

computed 預設只有 getter 屬性，但也可以經由以下方法重設 setter 屬性。

```htmlmixed=
<div id="app">
  <p>fullName (computed)：{{ fullName }}</p>
</div>
```
```javascript=
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.firstName 和 vm.lastName 也會相對應地被更新。

更多關於 getter 和 setter 的知識可以參考這篇文章：[那些關於 Vue 的小細節 - Computed 中 getter 和 setter 觸發的時間點](https://pjchender.blogspot.com/2017/05/vue-computed-getter-setter.html)

## 與 Methods 的不同

使用 methods 改寫上例，也能得到相同的效果。
```htmlmixed=
<p>Reversed message: "{{ reverseMessage() }}"</p>
```
```javascript=
methods: {
  reverseMessage: function () {
    return this.message.split('').reverse().join('')
  }
}
```

不同的是，computed 是根據相依的資料改變時才做計算，而 method 是不管有無相依都會計算，只要每次重新渲染畫面就會執行一次。

### 使用 Date.now() 的陷阱

```htmlmixed=
<div id="app">
  <p>message：{{ message }}</p>
  <p>now (computed)：{{ now }}</p>
  <p>getNow (method)：{{ getNow() }}</p>
</div>
```
```javascript=
var vm = new Vue({
  el: '#app',
  data: {
    message: 'Hello World!',
  },
  computed: {
    now: function() {
      return Date.now();
    },
  },
  methods: {
    getNow: function() {
      return Date.now();
    },
  },
});
```
在一開始都會執行 computed 和 methods 的時候，沒有任何差異。

![](https://i.imgur.com/XScJpin.png)


當改變 message 時，由於 now 這個計算屬性沒有用到任何相依的資料，因此不重新計算取值；但 getNow 是方法，無論是否有相依，只要有變動都會重新計算。

![](https://i.imgur.com/ntPEWys.png)


## 與 Watch 的不同

```htmlmixed=
<div id="demo">{{ fullName }}</div>
```

使用 watch
```javascript=
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
    }
  }
})
```
使用 computed
```javascript=
var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar'
  },
  computed: {
    fullName: function () {
      return this.firstName + ' ' + this.lastName
    }
  }
})
```

使用 watch：多了一個 fullName 屬性，而且其相依的屬性有幾個，就得多幾個 watcher 監聽。

## 使用 computed 時機

* 需要資料產生資料時
* 為了達到更好效能，不需要每次更新方法時


## 參考資料
* [Vue.js - Computed Properties and Watchers](https://vuejs.org/v2/guide/computed.html)
* [Vue.js: 計算屬性 Computed](https://cythilya.github.io/2017/04/15/vue-computed/)
* [Vue.js Core 30天屠龍記(第7天): 計算屬性](https://ithelp.ithome.com.tw/articles/10203948)




