computed 有 getter(取值) 和 setter (寫入值)可使用,但預設只會有 getter 使用,因此 computed 預設是唯讀,不能寫入值。每次建立元件時,都會先跑一次 computed 裏的 getter 來取得此 computed 函式裏的值。之後如果該 computed 函式裏的依賴沒有變化,就不會再跑此 computed 函式,即是不會跑 此函式的getter,並只會一直回傳之前緩存起來的值。
另外,如果要使用 setter,我們可以透過在 computed 屬性裏建立物件的方法來建立 getter 和 setter。
以下會再作詳細解說。
預設 computed 只有 getter,意思是我只能透過 computed 函式 來取值。
例如我嘗試在 mounted,觸發 total 函式裏的 setter:
<div id="app">
<p> {{ total }} </p>
</div>
data() {
return {
price: 100,
discount: 0.8
}
},
computed: {
total() {
return this.price * this.discount
}
},
mounted() {
this.total = 1000
}
報錯:
[Vue warn]: Write operation failed: computed property 'total' is readonly.
Vue 官網有提到,雖然預設只有 getter 可使用,但我們可以使用物件,並在裏面使用 getter 和 setter。
當你打開 console 查看會看到其實 computed 屬性(以 total 為例)也會有 set:

以下例子示範如何使用預設沒有的 setter。注意:需要使用物件來建立 getter 和 setter:
<div id="app">
<p> 定價: {{ price }} </p>
<p>折扣:{{ discount }} </p>
<p>折扣價:{{ total }}</p>
<button @click="changeComputed">按此隨機產生折扣</button>
</div>
data() {
return {
price: 100,
discount: 0.5
}
},
computed: {
// 需使用物件
total: {
get() {
console.log('觸發 getter!')
return this.price * this.discount
},
set(newVal) {
console.log('觸發 setter!')
this.discount = newVal
}
}
},
methods: {
changeComputed() {
// 觸發 set,再觸發 get
this.total = Number(Math.random().toFixed(1))
}
}
結果:

程式碼:
https://codepen.io/alysachan/pen/QWgojov
this.total = Number(Math.random().toFixed(1)) 這行雖然看來好像怪怪的?看似是直接把 total 改為隨機產生出來的 discount。但事實上,這裏所做的事是觸發 set 函式,並非修改 total 的值。
重溫一下原生 JavaScript 裏 set(setter) 的用法:
const obj = {
num: 0,
get add(){
return this.num
},
set add(newVal){
this.num += newVal
}
}
// 使用 get
console.log(obj.add) // 0
// 使用 set
console.log(obj.add = 100) //100
以上 obj.add = 100,就是把 100 帶進去 add 函式裏,並非改掉 add 函式所回傳的值。
因此,回到 Vue 的例子:this.total = Number(Math.random().toFixed(1))。就是把右邊的值,帶進去 total 的 set 函式裏,也即是 newVal 參數的值。並且修改了 discount 的值。
但為什麼畫面明明顯示total 的值被修改了?因為在 computed 函式裏,所有用到的 data 資料,都會是該函式的依賴。因此當 this.discount 有變化時,就會觸發 total 的更新。
所以整個運作次序就是:
set,修改 discount
打開 console 會看到,先觸發 setter,之後才是 getter:

注意,觸發了 set 不代表一定會觸發 get。如果在 set 裏沒有修改到 get 裏的任何一個依賴,get 就不會被觸發,即是不會更新在畫面中 total 的值。例如我只是在 set 裏印出參數:
total: {
get() {
return this.price * this.discount
},
set(newVal) {
console.log(newVal)
}
}
如果畫面中沒有用到 total,只剩下 price 和 discount:
<div id="app">
<p> 定價: {{ price }} </p>
<p>折扣:{{ discount }} </p>
<!-- <p>折扣價:{{ total }}</p> -->
<button @click="changeComputed">按此隨機產生折扣</button>
</div>
這情況裏,即使按按鈕,修改了 this.discount,也不會觸發 total 裏的 get。反之,只會一直印出 觸發 setter! 文字。除非你打開了 Vue devtool 檢查工具看一次,之後 Vue 才會執行 getter,並印出 觸發 getter! 文字。
因此可以總結一句,如果在畫面沒用到此 computed 函式,而且沒有在其他程式碼裏有使用過此 computed 函式的值。即代表不會跑該 computed 函式裏的 get,也就是沒有更新此值。
不過這情況不用怎樣擔心,即是如果在畫面上沒用過此值,但你在其他程式碼用到時,還是會寫 this.total。一旦寫了 this.total,就會觸發 total 的 getter,也就一定會取得最新的值。
當然,另一個情況就是當依賴的資料沒變化,就不會執行 getter,並且會一直回傳之前緩存起來的值,也就是 computed 的緩存特性。
例如改一下之前的例子,按按鈕後,把 discount 改為 0.5。結果只會一直印出「觸發 setter!」,因為資料裏的 discount 也是 0.5,結果就沒變化:
methods: {
changeComputed() {
// 只會觸發 set
// 一直都是改為 0.5
this.total = 0.5
}
},
computed 預設只使用 getter,沒有 setter。因此 computed 函式只會是唯讀。computed 裏加入 setter,但注意要以物件型別來寫,並在裏面加入 getter 和 setter。computed 函式的值,而在程式碼中也沒有用過此值,Vue 就不會跑該函式裏的 getter,也不知道會回傳什麼值。那些關於 Vue 的小細節 - Computed 中 getter 和 setter 觸發的時間點
Vue 筆記 - Computed 的 get() 與 set()
属性的 getter 和 setter