iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 8
0
自我挑戰組

每天來點 Vue.js 吧系列 第 8

Vue computed 與 method 的差異比較

tags: Vuejs

computed 與 method 的混淆

在模板中要對資料計算或是轉換時,computedmethod 往往能替我們做到同樣的事情,例如今天需要組合 姓氏名稱 成為 全名,我可以選擇 computed 完成,同時 method 也可以替我完成同樣任務(由於模板對於 expression 的支持,使得 Function call 也可以寫在模板中。)

 computed: {
    name: {
      get: function () {
        return this.lastName + " " + this.firstName;
      },
      set: function (value) {
        const name = value.split(" ");
        this.lastName = name[0];
        this.firstName = name[1];
      }
    }
  }
 methods: {
    name: function () {
        return this.lastName + " " + this.firstName;
      }
  }

由於兩者皆能幫我們達成需求,那麼何時該使用 computed?何時又該使用 methods 就成了令人困惑的問題,不過兩者其實並不相同,自官方教學中的敘述我們可以得知兩者的差距:

Vuejs.org 2.x 官網明確地點出了兩者的差距:

計算屬性是基於它們的響應式依賴進行緩存的;相比之下,每當觸發重新渲染時,調用方法將總會再次執行函數。

簡單來說 computed 只會在其依賴的資料 改變 的時候 重新計算求值,儘管在模板中多次調用 computed、或是改變其他資料觸發畫面 重新渲染 這件事,只要 computed property 原始依賴響應的資料 沒有更動Vue 並不會重新求取 computed property,而是訪問其 緩存結果;另外,method 則是一旦觸發重新渲染便會重新執行函式。

computed 何時調用緩存

下圖為範例,來實證 computed在模板中多次調用相同發生重新渲染 時,只要響應資料沒有變動,便不會重新計算取值,而是調用緩存的這件事。

computed property elapse 為計算 2020/09/022020/09/22 的差距日期。

const vm = new Vue({
  el: ".app",
  data: {
    startDay: "2020/09/02",
    endDay: "2020/09/22",
    text: "恩~"
  },
  computed: {
    elapse() {
      console.log("我執行一次了,computed");
      const startDayArgumment = this.startDay.split("/");
      const endDayArgument = this.endDay.split("/");
      const startTime = new Date(startDayArgumment);
      const endTime = new Date(endDayArgument);
      const oneDayMilliseconds = 1000 * 60 * 60 * 24;
      const elapse =
        (endTime.getTime() - startTime.getTime()) / oneDayMilliseconds;
      return elapse;
    }
  }
});

依照剛才所說,computed 只會在其依賴的資料改變的時候 重新計算求值,於是我們透過對 computed property 中添加 comsloe.log("我執行一次了,computed") 驗證該 computed 在以下兩點情境中是否會重新求值,一旦重新求值,我們可以自 console 面板中快速確認:

  1. 在模板中多次調用相同 computed property
  2. 發生重新渲染

1. 在模板中多次調用相同 computed property

<main class="app">
  <h1>{{ elapse }}</h1>
  <h1>{{ elapse }}</h1>
  <h1>{{ elapse }}</h1>
</main>
結果:computed property 無重新求值計算

如同上述所言,在 elapse 所依賴的 startDay 以及 endDay 沒有更動的情況下,Vue 會訪問先前 elapse 的緩存結果,而不會重新取值,所以 console 面板並沒有任何 我執行一次了,computed 的提醒。

2. 更改其他 data,觸發畫面重新渲染

這個時候要在 data 中添加 text 屬性,並且在模板中使用 text,藉由稍後更改 text 觸發重新渲染 re-render

<main class="app">
  <h1>{{ text + startDay +" 和 "+ endDay +" 差距 " + elapse() +" 天" }}</h1>
</main>

接著在 console 中輸入以下更動,觸發重新渲染

vm.text = 'change'

結果:computed property 無重新求值計算

如同上述所言,在 elapse 所依賴的 startDay 以及 endDay 沒有更動的情況下,Vue 會訪問先前 elapse 的緩存結果。

說明完 computed property 的特性,以下簡略 computed 適用的場合:

  1. 需要自 現有資料 中組合、轉換成 新資料
  2. 需要在模板中多次調用該資料
  3. 需要在模板中直接引用需要經過一些計算求得結果的資料

method 緩存範例

看完了 computed,來看看相同情境下,method 的行為吧!

const vm = new Vue({
  el: ".app",
  data: {
    startDay: "2020/09/02",
    endDay: "2020/09/22",
    text: "恩~"
  },
  methods: {
    elapse() {
      console.log("我執行一次了,method");
      const startDayArgumment = this.startDay.split("/");
      const endDayArgument = this.endDay.split("/");
      const startTime = new Date(startDayArgumment);
      const endTime = new Date(endDayArgument);
      const oneDayMilliseconds = 1000 * 60 * 60 * 24;
      const elapse =
        (endTime.getTime() - startTime.getTime()) / oneDayMilliseconds;
      return elapse;
    }
  }
});

同樣確認以下兩項情境,由於 methods 一旦畫面 re-render 便會重新計算,所以下列結果都會看到 method 重新取值:

  1. 在模板中多次調用相同 methods
  2. 發生重新渲染

1. 在模板中多次調用相同 methods

<main class="app">
  <h1>{{ elapse() }}</h1>
  <h1>{{ elapse() }}</h1>
  <h1>{{ elapse() }}</h1>
</main>

可以看到 method 乖乖按照調用的次數調用了三次 XD。

2. 更改其他 data,觸發畫面重新渲染

這個時候同樣在 data 中添加 text 屬性,並且在模板中使用 text,藉由稍後更改 text 觸發重新渲染 re-render

<main class="app">
  <h1>{{ text + startDay +" 和 "+ endDay +" 差距 " + elapse() +" 天" }}</h1>
</main>

接著在 console 中輸入以下更動,觸發重新渲染

vm.text = 'change'

可以看到一旦 re-render method 也重新調用。

結語

看完以上的範例,來做個小總結,computed 優點在於由於 緩存 的特性,一旦使用的大量的計算,在既有響應依賴資料沒有更動的前提下,computed 不會重新計算求值,減少性能上的開銷,反之,若是有需要隨時更新、不希望緩存的情境,則可以使用 method 替代,不過目前使用上 method 更常作為事件的方法調用,感謝看到這裡的你,我們明天見~。


若是文中有任何錯誤、錯字、想討論的內容,歡迎各位大大不吝鞭笞指正、交流分享,筆者不慎感激 ✦ ✦ ✦

▶︎ 筆者 github:https://github.com/YUN-RU-TSENG
▶︎ 老王賣瓜之筆者另一篇鐵人:每天來點 CSS Specification

▶︎ 倘若不斷向深處扎根,似乎就能茁壯成長 - RM


參考資料:

  1. Vuejs.org 2.x
  2. The difference between COMPUTED and METHODS in Vue.js | by Luca Spezzano | NotOnlyCSS | Medium

上一篇
Vue computed property `getter` 與 `setter` 的那些事
下一篇
Vue computed 與 watch 差異
系列文
每天來點 Vue.js 吧30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
Chris
iT邦新手 4 級 ‧ 2020-09-24 00:06:53

computed 是前端造出來的欄位

英國麵包、德國麵包、法國麵包通通都有,就是沒有屬於日本麵包;既然這樣,今後只好自己創造

突然想到這句 XD

我要留言

立即登入留言