vue中的计算属性computed的实现原理


1、计算属性默认不执行

     Object.defineProperty =>getter
     只有在取值的时候才执行
     多次取值如果依赖的值不变化就只执行一次,是缓存的原因
     依赖的值变化了,需要重新执行
     dirty 表示这个值是不是脏的,默认是true (取值后变为false),依赖的值变化了。 dirty:true

2、只能有get和set,或者只有get  不能没有set


const vm = new Vue({
  computed: {
    fullName: {
      get() {
        console.log("ooo");
        return this.firstName + this.lastName;
      },
      set(newValue) {
        console.log(newValue);
      },
    },
  },
});

function initComputed(vm, computed) {
  const watchers = (vm._computedWatchers = {});
  for (let key in computed) {
    const userDef = computed[key];
    // 依赖的属性变化 就重新取值get
    let getter = typeof userDef == "function" ? userDef : userDef.get;
    console.log(getter);

    // 每个计算属性本质就是watcher
    // 将watcher和属性做一个映射
    watchers[key] = new Watcher(vm, getter, () => {}, { lazy: true }); //默认不执行

    // 将key定义在vm上。
    defineComputed(vm, key, userDef);
  }
}

function defineComputed(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);
}

function createComputedGetter(key) {
  return function computedGetter() {
    //取计算属性的值,走的是这个函数

    // 所有的计算属性,通过key可以拿到对应的watcher,这个watcher包含了getter
    let watcher=this._computedWatchers[key];
    // 脏就是 要调用用户的getter  不脏就是不要调用getter

    if(watcher.dirty){   //根据dirty来判断是否需要重新求值
        watcher.evaluate();     //脏就代表能取值,能调get方法。
    }

    return watcher.value;
  }
}

// watch 是回调 computed是getter和setter。
// 如果是计算属性, 那么默认值lazy:true, dirty:true


function evaluate(){ 
    this.dirty=false;   //为false表示取过值了
    this.value=this.get();   //用户的getter
}


// 只有get方法的时候有缓存,set修改不影响
// 在页面中直接写fullName时,fullName不会去收集渲染watcher
// firstName 是在计算属性中使用的,所以他会收集计算属性watcher   没有收集渲染watcher
// dep.subs是个数组,用来存watcher
// Dep.target只有一个watcher  

/***
 * 计算属性中的值应该 记录计算属性watcher 和 渲染watcher 
 * 因为fullName 没有dep  没有收集的功能
 * Dep.target 上赋值一个渲染watcher,又将Dep.target设置为计算属性watcher
 * 
 */

 function depend(){
     let i=this.deps.length;
     while(i--){
         this.deps[i].depend();
     }
 }

 /**
  * 1个watcher 对应多个dep
  * 属性变化  通知计算属性watcher   然后再重新渲染watcher
  * fullName没有渲染watcher fullName对应的计算属性watcher 
  * 通过计算属性watcher  找到dep 让dep收集的是渲染watcher  因为fullName没有dep  没有收集的功能。
  * 计算属性和watch 都是一个watcher
  */

 

相关推荐
©️2020 CSDN 皮肤主题: 终极编程指南 设计师:CSDN官方博客 返回首页