You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
constcomputedWatcherOptions={computed: true}// 定义computed属性functioninitComputed(vm: Component,computed: Object){// 先声明一个computedWatcher空对象constwatchers=vm._computedWatchers=Object.create(null)// 判断是不是服务端渲染constisSSR=isServerRendering()// 遍历computed中的对象for(constkeyincomputed){constuserDef=computed[key]// 获取属性的getter方法,这里有两种情况:是函数就直接获取,是对象就获取get值constgetter=typeofuserDef==='function' ? userDef : userDef.getif(process.env.NODE_ENV!=='production'&&getter==null){warn(`Getter is missing for computed property "${key}".`,vm)}// 非服务端渲染,new一个computed watcher实例。if(!isSSR){watchers[key]=newWatcher(vm,getter||noop,noop,computedWatcherOptions)}// 不存在Vue实例中,就去定义if(!(keyinvm)){defineComputed(vm,key,userDef)}elseif(process.env.NODE_ENV!=='production'){// 开发环境下判断computed的key不能跟data或props同名if(keyinvm.$data){warn(`The computed property "${key}" is already defined in data.`,vm)}elseif(vm.$options.props&&keyinvm.$options.props){warn(`The computed property "${key}" is already defined as a prop.`,vm)}}}}
exportdefaultclassWatcher{constructor(vm: Component,expOrFn: string|Function,cb: Function,options?: ?Object,isRenderWatcher?: boolean){this.vm=vmif(isRenderWatcher){vm._watcher=this}vm._watchers.push(this)// optionsif(options){this.deep=!!options.deepthis.user=!!options.userthis.computed=!!options.computedthis.sync=!!options.syncthis.before=options.before}else{this.deep=this.user=this.computed=this.sync=false}this.cb=cbthis.id=++uid// uid for batchingthis.active=truethis.dirty=this.computed// for computed watchersthis.deps=[]this.newDeps=[]this.depIds=newSet()this.newDepIds=newSet()this.expression=process.env.NODE_ENV!=='production'
? expOrFn.toString()
: ''// 对于computed watcher这里是一个getter函数,赋值给getterif(typeofexpOrFn==='function'){this.getter=expOrFn}else{this.getter=parsePath(expOrFn)if(!this.getter){this.getter=function(){}process.env.NODE_ENV!=='production'&&warn(`Failed watching path: "${expOrFn}" `+'Watcher only accepts simple dot-delimited paths. '+'For full control, use a function instead.',vm)}}// 计算属性执行到这里为trueif(this.computed){// 和其他watcher的区别,计算属性这里并不会立刻返回求值this.value=undefined// 创建了该属性的消息订阅器this.dep=newDep()}else{this.value=this.get()}}
exportdefaultclassDep{statictarget: ?Watcher;id: number;subs: Array<Watcher>;constructor(){this.id=uid++this.subs=[]}addSub(sub: Watcher){this.subs.push(sub)}removeSub(sub: Watcher){remove(this.subs,sub)}depend(){if(Dep.target){Dep.target.addDep(this)}}notify(){// stabilize the subscriber list firstconstsubs=this.subs.slice()for(leti=0,l=subs.length;i<l;i++){subs[i].update()}}}
工具推荐
推荐vue/cli的一个工具,零配置直接运行vue文件。
安装方法:
使用方法:
computed
这篇文章分享一下computed计算属性的实现原理。首先分享一个工作中遇到的code review问题!利用3分钟先看一个例子:
按钮点击前后分别输出什么?

上面的答案是不是如你所想呢?
又或者有为什么点击后
valueText
不是true
的疑问?如果有,就继续往下通过源码分析computed的原理!在Vue实例初始化时,注意到有一个
initState
的方法。这个方法就是初始化 props、data、methods、watch、computed 等属性。进入函数体里面继续看:非常简单,就是对一些属性做初始化调用,本文重点是
computed
!好,继续看initComputed
的内容:到这里,我们先不去深入
computed watcher
实例的声明,先看defineComputed
:sharedPropertyDefinition
结构如下:sharedPropertyDefinition 的 get 函数也就是
createComputedGetter(key)
的结果:当计算属性被调用时便会执行 get 访问函数,从而关联上观察者对象 watcher 然后执行
wather.depend() 收集依赖和 watcher.evaluate() 计算求值。
OK,下面我们回到
computed watcher
的实例化:这里的参数意义都比较清晰。 vm 指的 Vue 实例, getter 指的是计算属性的 getter 方法, computedWatcherOptions 即表明这是一个 computed watcher 。
这里Watcher和Dep的关系就是:
当获取到计算属性的值时,就会执行getter函数,即
再看到watcher对象中的depend和evaluate方法:
以上就是计算属性getter的整个过程,这里稍微总结一下:
计算属性的setter的流程比较简单:
现在再回头去看第一个问题的答案就一清二楚了。计算属性
valueText
因为 this.abc 为 undefined 并没有收集到 this.abc 的变化。所以点击之后是valueText
并不会改变。如果将两个属性调换位置,那么就如我们所愿了:这里可以得出结论:
The text was updated successfully, but these errors were encountered: