# 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 的時候,沒有任何差異。

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

## 與 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)