Vue 計(jì)算屬性原理篇

通常我們不需要頻繁的去更新模板上的屬性值,則會(huì)采用computed,因?yàn)樗哂芯彺婀δ?,可以提高性能?/h4>

computed有兩種寫法
1、
<div id="app">{{fullName}}</div>     
   let vm = new Vue({
            el:'#app',
            data(){
                return {
                    // arr:[[1,2,3]],
                    // name:'123',
                    firstName:'yan',
                    lastName:'liying'
                }
            },
            computed:{
                fullName:{
                    get(){
                        return this.firstName + this.lastName;
                    },
                    set(val){
    
                    }
                }
            },
})
2、
<div id="app">{{fullName}}</div>     
   let vm = new Vue({
            el:'#app',
            data(){
                return {
                    // arr:[[1,2,3]],
                    // name:'123',
                    firstName:'yan',
                    lastName:'liying'
                }
            },
           computed:{
                fullName(){
                    return this.firstName + this.lastName
                }
            },
})
vue中初始化computed,每一個(gè)計(jì)算屬性的本質(zhì)就是watcher,創(chuàng)建計(jì)算屬性的watcher時(shí),會(huì)傳入一個(gè)懶惰屬性,來(lái)控制computed緩存的功能,默認(rèn)是執(zhí)行的,先處理為vm._computedWatchers對(duì)象,每個(gè)key對(duì)應(yīng)一個(gè)watch實(shí)例。進(jìn)而能夠獲取到當(dāng)前這個(gè)計(jì)算屬性的dirty,來(lái)控制是來(lái)重新觸發(fā)get,還是走上一次的緩存;
function initComputed(vm, computed) {
  for (let key in computed) {
    const userDef = computed[key];
    let watch = vm._computedWatcher = {}
    //依賴的屬性變化就重新取值 get
    let getter = typeof userDef == "function" ? userDef : userDef.get;
    //每個(gè)計(jì)算屬性本質(zhì)就是watcher
    watch[key] = new Watcher(vm, getter, () => {}, { lazy: true }); //默認(rèn)執(zhí)行
    //將key定義在vm上
    defineProperty(vm, key, userDef);
  }
}
function createComputedGetter(key){
    return function computedGetter(){
        let watcher = this._computedWatcher[key];
        if(watcher.dirty){
            watcher.evaluate();
        }
        //如果當(dāng)前取完值后 dep.target還有值,需要繼續(xù)向上收集
        if(Dep.target){
            //計(jì)算屬性watcher,firstName,lastName
            watcher.depend();//watcher對(duì)應(yīng)了多個(gè)dep
            console.log(Dep.target,'---tera');
        }
        return watcher.value;
    }
}
//computed 就是一個(gè)defineProperty
function defineProperty(vm, key, userDef) {
  let sharedProperty = {};
  if(typeof userDef == 'function'){
      sharedProperty.get = userDef;
  }else{
      sharedProperty.get = createComputedGetter(key);
      sharedProperty.set = userDef.set;
  }
  Object.defineProperty(vm, key, sharedProperty)
}
watcher中的dirty默認(rèn)是true,是執(zhí)行狀態(tài),會(huì)觸發(fā)watcher中的evaluate,方法,evaluate方法中會(huì)調(diào)用get方法,并且同時(shí)將當(dāng)前的watcher中的dirty置為false,下一次不會(huì)執(zhí)行。
class Watcher {
  constructor(vm, exporOrFn, cb, options = {}) {
    this.vm = vm;
    this.exporOrFn = exporOrFn;
    this.options = options;
    this.cb = cb;
    this.id = id++;
    this.user = !!options.user; //是否是用戶調(diào)用
    this.lazy = !!options.lazy; //computed懶執(zhí)行的flag
    this.deps = [];
    this.dirty = this.lazy;
    this.depsId = new Set();
    //默認(rèn)應(yīng)該讓exportOrFn執(zhí)行,exportOrFn做了什么事?去render上取值
    if (typeof exporOrFn == "string") {
      this.getter = function () {
        let arr = exporOrFn.split(".");
        let obj = vm;
        for (var i = 0; i < arr.length; i++) {
          obj = obj[arr[i]];
        }
        return obj;
      };
    } else {
      this.getter = exporOrFn;
    }
    //value 值是第一次渲染的value
    this.value = this.lazy ? undefined : this.get(); //默認(rèn)初始化要取值
  }
  get() {
    //稍后用戶更新時(shí),可以重新調(diào)用getter方法
    //defineProperty.get,每個(gè)屬性都可以收集自己的watcher,每個(gè)屬性都有一個(gè)依賴收集的對(duì)象 dep
    //一個(gè)屬性可以對(duì)應(yīng)多個(gè)watcher,一個(gè)watcher也可以對(duì)應(yīng)多個(gè)屬性
    pushTarget(this);
    const value = this.getter.call(this.vm);
    popTarget(this);
    return value;
  }
  update() {
    if (this.lazy) {
      this.dirty = true;
    } else {
      //每次更新時(shí) this 多次調(diào)用update 我希望現(xiàn)將watcher緩存下來(lái),等一會(huì)一起更新
      queueWatcher(this);
    }
  }
  evaluate() {
    this.dirty = false;
    this.value = this.get();
  }
} 

總結(jié)

  • 初始化 data 和 computed,分別代理其 set 和 get 方法,對(duì) data 中的所有屬性生成唯一的 dep 實(shí)例

  • 對(duì) computed 中的 屬性生成唯一的 watcher,并保存在 vm._computedWatchers 中

  • 訪問(wèn)計(jì)算屬性時(shí),設(shè)置 Dep.target 指向 計(jì)算屬性的 watcher,調(diào)用該屬性具體方法

  • 方法中訪問(wèn) data 的屬性,即會(huì)調(diào)用 data 屬性的 get 方法,將 data 屬性的 dep 加入到 計(jì)算屬性的 watcher , 同時(shí)該 dep 中的 subs 添加這個(gè) watcher

  • 設(shè)置 data 的這個(gè)屬性時(shí),調(diào)用該屬性代理的 set 方法,觸發(fā) dep 的 notify 方法

  • 因?yàn)闀r(shí) computed 屬性,只是將 watcher 中的 dirty 設(shè)置為 true

  • 最后,訪問(wèn)計(jì)算屬性的 get 方法時(shí),得知該屬性的 watcher.dirty 為 true,則調(diào)用 watcher.evaluate() 方法獲取新的值

參考:http://www.itdecent.cn/p/a79806d317a4
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容