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() //创建消息订阅器
}
}
//处理自己所依赖的属性
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的主要内容,如果未能解决你的问题,请参考以下文章