成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Vue3源碼解析計劃之計算屬性為什么比普通函數妙?

開發 前端
計算屬性是Vue開發中一個非常實用的API,它允許用戶自定義一個計算方法,然后根據一些依賴的響應式數據計算出新值并返回。當依賴發生變化時,計算屬性會自動重新計算獲取新值,使用方便。

[[440389]]

本文轉載自微信公眾號「前端萬有引力」,作者 一川 。轉載本文請聯系前端萬有引力公眾號。

寫在前面

計算屬性是Vue開發中一個非常實用的API,它允許用戶自定義一個計算方法,然后根據一些依賴的響應式數據計算出新值并返回。當依賴發生變化時,計算屬性會自動重新計算獲取新值,使用方便。我們看出計算屬性本質上是對依賴的計算,為什么不直接使用函數呢?在Vue3中的計算屬性又是如何實現的呢?

計算屬性 computed

我們先簡單看個例子,我們看到再設置了計算屬性addOne后,直接改變addOne.value的值會報錯,只能通過改變原始值count.value才不會報錯。這是因為:

  • 如果傳遞給computed的是一個函數,那就是一個getter函數,只能獲取它的值,而不能直接修改它
  • 在getter函數中,根據響應式對象重新計算出新值,叫做計算屬性,這個響應式對象叫做計算屬性的依賴
  1. const count = ref(1); 
  2. const addOne = computed(()=>count.value+1); 
  3. console.log(addOne.value);//2 
  4. addOne.value++;//error 
  5. count.value++; 
  6. console.log(count.value);//3 

那么,我們應該如何修改addOne.value值呢?那就是在computed中設置set函數,進行自定義修改值。

  1. const count = ref(1); 
  2. const addOne = computed({ 
  3.  get:()=>count.value+1, 
  4.   set:val=>count.value=val-1 
  5. }); 
  6. addOne.value = 1; 
  7. console.log(count.value);//0 

我們研究源碼:

  1. export function computed<T>( 
  2.   getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T> 
  3. ) { 
  4.   let getter: ComputedGetter<T> 
  5.   let setter: ComputedSetter<T> 
  6.  
  7.   // 如果傳入是 function 說明是只讀 computed 
  8.   if (isFunction(getterOrOptions)) { 
  9.     getter = getterOrOptions 
  10.     setter = __DEV__ 
  11.       ? () => { 
  12.           console.warn('Write operation failed: computed value is readonly'
  13.         } 
  14.       : NOOP 
  15.   } else { 
  16.     // 不是方法說明是自定義的 getter setter  
  17.     getter = getterOrOptions.get 
  18.     setter = getterOrOptions.set 
  19.   } 
  20.  
  21.   let dirty = true 
  22.   let value: T 
  23.   let computed: ComputedRef<T> 
  24.  
  25.   // 創建 effect, 我們在看 effect 源碼時知道了傳入 lazy 代表不會立即執行,computed 表明 computed 上游依賴改變的時候,會優先 trigger runner effect, scheduler 表示 effect trigger 的時候會調用 scheduler 而不是直接調用 effect 
  26.   const runner = effect(getter, { 
  27.     lazy: true
  28.     // mark effect as computed so that it gets priority during trigger 
  29.     computed: true
  30.     scheduler: () => { 
  31.       // 在觸發更新時把dirty置為true, 不會立即更新  
  32.       if (!dirty) { 
  33.         dirty = true 
  34.         trigger(computed, TriggerOpTypes.SET'value'
  35.       } 
  36.     } 
  37.   }) 
  38.  
  39.   // 構造一個 computed 返回 
  40.   computed = { 
  41.     __v_isRef: true
  42.     // expose effect so computed can be stopped 
  43.     effect: runner, 
  44.     get value() { 
  45.       // dirty為ture, get操作時,執行effect獲取最新值 
  46.       //  
  47.       if (dirty) { 
  48.         value = runner() 
  49.         dirty = false 
  50.       } 
  51.       // dirty為false, 表示值未更新,直接返回  
  52.       track(computed, TrackOpTypes.GET, 'value'
  53.       return value 
  54.     }, 
  55.     set value(newValue: T) { 
  56.       setter(newValue) 
  57.     } 
  58.   } as any 
  59.   return computed 

computed計算屬性有兩個特點:

  • 延時計算:只有當我們訪問計算屬性時,真正運行computed getter函數計算
  • 緩存:它的內部會緩存上次的計算結果value,而只有dirty為true時才會重新計算,如果訪問計算屬性時dirty為false,那么直接返回這個value

那么,計算屬性的優勢是:只要依賴不變化,就可以使用緩存的value而不用每次再渲染組件的時候都執行函數去計算。

做個嵌套計算的小例子,我們看到:對于addOne而言,它收集的依賴是組件副作用渲染函數,而對于count而言,它收集的依賴是addTwo內部的runner函數。當我們修改count值,會進行派發通知,先運行addOne中的setter函數,此時addOne中的dirty值變成true,然后trigger函數再次派發通知;接著運行addTwo中的setter函數,此時把addTwo中的dirty值設置為true;當我們再次訪問addTwo中的值時,發現dirty值為true,就會執行addTwo的computed函數,會先去執行addOne.value + 1,再去執行addOne的computed函數中的count.value + 1。這樣就得到最后打印出來的值為2。

  1. const count = ref(0); 
  2. const addOne = computed(()=>{ 
  3.  return count.value + 1;//1 
  4. })  
  5.  
  6. const addTwo = computed(()=>{ 
  7.  return addOne.value + 1;//2 
  8. }) 
  9.  
  10. console.log(addTwo.value);//2 

得益于computed計算屬性的巧妙設計,無論嵌套多少層都能夠正常運行。

  1. import {ref,computed} from "vue"
  2. import {effect} from "@vue/reactivity"
  3.  
  4. const count = ref(0); 
  5. const addOne = computed(()=>{ 
  6.  return count.value + 1; 
  7. }) 
  8.  
  9. effect(()=>console.log(addOne.value+count.value)) 
  10.  
  11. function add(){ 
  12.  count.value++; 
  13.  
  14. add(); 

我們看到上面代碼最終輸出結果是:1 3 3

當我們第一次執行addOne的computed計算屬性時,count.value值還是0,而addOne.value的值為1,將會觸發并執行effect,此時打印出來還是1。而后執行add()函數,會進行修改count.value的值,會觸發并執行effect函數,因為addOne也是effect的依賴,addOne的runners函數也是count.value的依賴,count.value值的修改會執行runners函數,會再次執行addOne的依賴,接著會觸發effect函數,因此會輸出兩次3。

computed函數返回的對象實際上劫持的是value屬性的getter和setter,但是為什么我們在組件的模板中訪問一個計算屬性變量,不用手動在后面加.value呢?

參考文章

  • 《Vue3核心源碼解析》
  • 《Vue中文社區》
  • 《Vue3中文文檔》

寫在最后

 

理解計算屬性的工作機制,能夠搞明白計算屬性嵌套場景代碼的執行順序,知道計算屬性的兩個特點--延時計算和緩存,在組件的開發中合理使用計算屬性。

 

責任編輯:武曉燕 來源: 前端萬有引力
相關推薦

2021-12-12 18:31:35

VNode組件Vue3

2021-01-20 14:25:53

Vue3CSS前端

2021-08-23 13:25:25

Vue3CSS前端

2023-12-11 07:34:37

Computed計算屬性Vue3

2023-07-26 17:40:50

2025-02-18 08:10:00

Vue 3JavaScrip開發

2025-03-26 10:29:22

Vue3前端API

2024-05-27 08:39:17

Vue3變量響應式

2021-09-22 07:57:23

Vue3 插件Vue應用

2021-11-26 05:59:31

Vue3 插件Vue應用

2021-12-13 00:54:14

組件Vue3Setup

2025-05-16 10:50:36

2024-07-04 08:56:35

Vue3項目Pinia

2020-09-17 07:08:04

TypescriptVue3前端

2022-01-26 11:00:58

源碼層面Vue3

2021-12-01 08:11:44

Vue3 插件Vue應用

2021-11-30 08:19:43

Vue3 插件Vue應用

2023-11-28 09:03:59

Vue.jsJavaScript

2021-09-27 06:29:47

Vue3 響應式原理Vue應用

2022-03-24 20:42:19

Vue3API 設計Vue
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 免费一二区 | 国产精品大全 | 美女天天操 | 一级片av| 日本手机看片 | 欧美电影一区 | 毛片一区二区 | 欧美日韩综合视频 | 日日操av | 午夜成人在线视频 | 99re在线观看| 天天插天天操 | 少妇精品亚洲一区二区成人 | 国产精品久久久乱弄 | 色一阁| 国产精品久久久久久一区二区三区 | 精品一区在线 | 成年女人免费v片 | 久国产视频 | 福利久久| 男女午夜免费视频 | av毛片免费 | 国产精品免费一区二区三区四区 | 一级高清视频 | 久草在线在线精品观看 | 午夜精品一区二区三区在线观看 | 亚洲精品久久久久久一区二区 | 天天色天天色 | av色站 | 日韩欧美国产电影 | a级片网站 | 99免费精品 | 亚洲视频欧美视频 | 欧美久久一区 | 精品久久香蕉国产线看观看亚洲 | 国产精品综合一区二区 | 久久国产成人午夜av影院武则天 | 欧美自拍第一页 | 成人精品免费视频 | 国产精品国产精品国产专区不蜜 | 久久久欧洲 |