vue computed

Posted yanze

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue computed相关的知识,希望对你有一定的参考价值。

new Vue后:
Vue.prototype._init= function(...){
  initLifecycle(vm) //初始化生命周期

  initEvents(vm) //初始化事件中心

  initRender(vm) //初始化渲染

  initState(vm) //初始化状态
}

function initState(){

  vm._watchers= [] //所有watcher

  const opts= vm.$options

  initProps()

  initMethods()

  initData()//先初始化data中的属性

  initComputed(vm, opts.computed) //初始化computed属性

  initWatch()

}

 

const computedWatcherOptions= {computed: true}

function initComputed(vm, computed){

  const watchers= vm._computedWatchers= Object.create(null) //所有computed属性

  for(const key in computed){

    const userDef= computed[key] //computed属性定义,函数形式或者对象形式(getter与setter)

    const getter= typeof userDef === ‘function‘? userDef: userDef.get //提取getter

    //创建computed属性的watcher,每个computed属性都有一个watcher

    watchers[key]= new Watcher(

      vm,

      getter,

      noop,

      computedWatcherOptions //computed watcher特有属性

    )

    //防止属性名被占用

    if(!(key in vm)){

      defineComputed(vm, key, userDef) //定义computed属性

    }

  }

}

 

//绑定体

const sharedPropertyDefinition= {

  enumerable: true, configurable: true,

  get: noop, set: noop

}

//绑定属性,定义getter、setter

function defineComputed(vm, key, userDef){

  //函数形式

  if(typeof userDef === ‘function‘){

    sharedPropertyDefinition.get= createComputedGetter(key)

    sharedPropertyDefinition.set= noop

  }

  //对象形式

  else {

    sharedPropertyDefinition.get= createComputedGetter(key)

  }

  //绑定

  Object.defineProperty(target, key, sharedPropertyDefinition)

}

 

//创建getter

function createComputedGetter(){

  //注意这里返回一个函数,此函数执行时机为计算属性被调用时

  return function computedGetter(){

    const watcher = this._computedWatchers[key] //该属性的watcher

    if(watcher){

      watcher.depend() //收集所依赖的

      return watcher.evaluate()

    }

  }

}

//当计算属性被调用(执行get方法),执行computedGetter函数

//访问属性->挟持对象的get方法->

//这里穿插一下watcher的构造函数

class Watcher{

  constructor(

    vm,

    expOrFn, //定义用的getter函数

    cb, //这里为noop

    options //{computed: true}

  )

  vm._watchers.push(this) //加入全局watcher数组

  if(options){

    this.computed= !!options.computed //true

    ....

  }

  this.id= ++uid

  this.dirty= this.computed //脏值检测

  this.deps= [] //订阅器(一个watcher可以有多个订阅器)

  this.getter= expOrFn //getter真多

  if(this.computed){

    this.value= undefined //计算属性的值
    this.dep= new Dep() //创建消息订阅器

  }

}

//处理自己所依赖的属性

Watcher.prototype.addDep = function addDep (dep) {
  var id = dep.id;
  if (!this.newDepIds.has(id)) {
    this.newDepIds.add(id);
    this.newDeps.push(dep);
    if (!this.depIds.has(id)) {
      dep.addSub(this);
    }
  }
};
 

class Dep {

  constructo(){

    this.uid= uid++

    this.subs= []

  }

  addSub(sub: Watcher){

    this.subs.push(sub)

  }

  removeSub(sub: Watcher){

  }

  //将自己加到watcher的订阅器数组中

  depend(){

    if(Dep.target){

      Dep.target.addDep(this)

    }

  }

  //通知订阅器里的每一个订阅者(watcher)去更新

  notify(){

    const subs= this.subs.slice()

    for(var i=0;i<subs.length;i++){

      subs[i].update()

    }

  }

}

 

回到computedwatcher的getter中:

if(watcher){

  watcher.depend() //收集所依赖自己的属性

  return watcher.evaluate() //处理所依赖的属性

}

 

watcher.depend= function(){

  //注意Dep.target为当前watcher

  if(this.dep && Dep.target){

    this.dep.depend() //结合Dep的定义 本质上是调用了watcher.addDep() 添加订阅器

  }

}

-----------------------------------------------------------------------------------------------------------------

 

watcher.evaluate= function(){

  //当所依赖的值发生改变的时候dirty为true,这就是依赖缓存!

  if(this.dirty){

    this.value= this.get()

    this.dirty= false

  }

  return this.value

}

备注:

get()

this.getter.call() 

调用定义的getter

 

computedWatcher.depend() 咋一看是处理所依赖的属性,其实恰恰相反,这里是处理依赖于自己的watcher

->computedWatcher.dep.depend()

->Dep.target.addDep(this/computedWatcher.dep) //这里发生在getter中,Dep.target为依赖于自己的watcherwatcher,this为computedwatcher

->watcher.addDep(this/computedWatcher.dep)

语义很重要!!总之核心就是computedWatcher.depend()调用Dep.target.addDep(computedWatcher.dep),computedWatcher将Dep.target(即watcher)添加到自己的subs中

以上是关于vue computed的主要内容,如果未能解决你的问题,请参考以下文章

VUE 监听 对象属性值变化的三种方式

vue3中的 computed

VUE3(setup响应式函数系统API)

VUE 监听 对象属性值变化的三种方式

Vue 中computed 和 watch 的区别

computed-计算属性