点击可打开demo
这里在一秒后改了数组里value属性的值
虽然数据有更新,但打开控制台,可以发现computed函数只在初始化时执行了一次
按理说一秒后改变了value值,应该执行两次才对呀?
但如果computed属性这样写,明确写明展开了每一项,获取到了value属性,就能执行第二次
vue的文档里提到,计算属性的方法只应该有单纯的计算,不要产生其他效果,像我们上面的demo,虽然数据有更新,但console.log没打印,这里的console.log其实就算是文档里的side effects
为什么会有这种表现呢?
看看vue的源码吧!顺便学习一下computed是如何实现的!
这里先说整体思路
这里用了proxy,对所有响应式对象加
proxy
,这样就能改他们的get和set等方法,然后当读取计算属性时,执行computed里的方法,执行的时候,会读取到其依赖的响应式对象,因为之前改了他们的set方法,所以此时能知道读取的是哪个对象的什么属性,此时就能把他加到computed属性的依赖中。但依赖的值发生改变,因为用proxy改过其get方法,同时之前收集过依赖,知道这个依赖值被哪些值所依赖,就能去触发更改。
接着看实际实现
我们对变量设为响应式对象,会用ref方法,ref方法的实现中调用了toReactive
toReactive调用了reactive
reactive调用createReactiveObject,并把mutableHandlers传入了参数
createReactiveObject使用了proxy,把mutableHandlers作为proxy的handler
然后我们看看handler是怎么做的
可以看到当get时,即获取响应式对象值时,调用了track方法,这里就是在收集依赖了,当我们在computed方法获取响应式对象时,这个computed就作为了target传入去,现在看看track方法做了什么
这里是{target -> key -> dep}的两个map,target就是每一个响应式对象,key就是这个对象上的属性名,dep里就存放了依赖这个属性的响应式对象列表,可以看到下面trackEffects函数里,有一行dep.add(activeEffect)
这里的activeEffect就是当前在运行的响应式对象,就是computed计算属性,被加到dep里了。因此,在computed里用到的其他响应式对象,当computed被执行时,其他响应式对象对应属性里就会维护一个列表,列表里放的是依赖这个属性的响应式对象,依赖收集完成。
之后就是触发了
这里用proxy改了set方法,会去调用trigger函数
看看trigger函数如何实现
trigger函数的target是改了值的响应式对象本身,key是更改的属性名,然后从刚刚说的{target -> key -> dep}两个map里,拿到依赖这个对象这个key的列表deps,这里还能看到如果改的是length,还会有额外操作,感兴趣的可以去看源码,在effect.ts文件。
之后就调用triggerEffects方法,参数其实就是deps,
然后就会去调用triggerEffect(说实话,我还没看到为啥355和360行的代码要这样写),这里如果有scheduler就会去执行,这里的scheduler是构造函数的第二个参数
能找到是在ComputedRefImpl的构造函数赋值的,这里会把dirty改为true,然后会调用triggerRefValue
triggerRefValue有调用triggerEffects了,是不是很熟悉?没错是解决假设你的计算属性被其他计算属性所以的,就会继续triggerEffects下去
那实际在哪里改变值呢?还记得刚刚把dirty改为true了吗?computed的实现了,get函数如果dirty为true,就会重新计算
这样,computed就更新了。
看完源码,终于懂了!如果在计算属性里没有明确获取某个响应式对象的某个key,那改了这个key,是不会重新执行computed的,所以就会有开头demo的现象。
因此,如果我仍想要有side effects,又不肯换watchers,可以明确获取一下会改变的属性值。但要记住这个知识点,可能相比有side effects就用watchers更复杂吧?
除非代码很多,难得改🐶
有不懂欢迎评论,一起探讨
小小经验:
Vue
中
计算属性
com
put
ed
没有被
触发
的排查
vue
中的
计算属性
可以绑定动态变量,当页面有变化时,
计算属性
就会自动更新
data中定义了相互独立并且不影响的变量
问题:
com
put
ed
中定义的一个动态变量在相关的属性发生变化时,并没有发生相对应地发生变化
比如,我点击全选或者商品的单选时,商品的总件数或者总价都没有发生变化
计算属性
的代码:
com
put
ed
: {
totalNum: function () {
let total = 0;
console.
vue
中
com
put
ed
计算属性
可以用来绑定动态变量,而且它可以实时刷新,并且也可以在watch中监控,所以本人很喜欢用这个东西,一般把需要随data中变量一起变化的属性全部放在这里面,data中只定义互相独立互相不影响的变量,这样可以极大地减少重复变量的定义,使代码结构清晰,也便于排查错误。
然后最近出现了一个问题,就是我在
com
put
ed
中定义的一个动态变量没有在相关属性发生变化后
触发
...
com
put
ed
是
vue
中的
计算属性
,在依赖的值发生变化的时候进行
重新
计算
,否则使用缓存。
而在面试中常被问及
com
put
ed
原理
,这篇文章主要作为我学习
com
put
ed
源码
的笔记。
前面说到
com
put
ed
只有在依赖发生变化才会
重新
计算
,那么如何得知
com
put
ed
的值发生了变化呢
这主要是Watcher中的dirty属性,dirty属性为true时,说明
com
put
ed
中的值需要
重新
计算
,dirty为false时,则说明依赖没有变化,不需要
重新
计算
当
计算属性
的值发生变化时,
计算属性
的watch
简述
vue
双向绑定
把一个普通
JavaScript
对象传给
Vue
实例的 data 选项,
Vue
将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。Object.defineProperty 是仅 ES5 支持,且无法 shim 的特性,这也就是为什么
Vue
不支持 IE8 以及更低版本浏览器的原因。
用户看不到 ...
一、
com
put
ed
和 watch 都可以观察页面的数据变化。当处理页面的数据变化时,我们有时候很容易滥用watch。 而通常更好的办法是使用
com
put
ed
属性,而不是命令是的watch回调。
二、
com
put
ed
:
在
vue
的 模板内({{}})是可以写一些简单的js表达式的 ,很便利。但是如果在页面中使用大量或是复杂的表达式去处理数据,对页面的维护会有很大的影响。这个时候就需要用到
com
put
ed
计算属性
来处理复杂的逻辑运算
1.优点:
在数据
未
发生变化时,优先读取缓存。
com
put
ed
计算属性
只有在相关的数据发生变化时才会改变要
计算
的属性,当相关数据没有变化是,它会读取缓存。而不必想 moth
ed
s方法 和 watch 方法是的每次都去执行函数。
2.setter 和 getter方法:(注意在
vue
中书写时用set 和 get)
setter 方法在设置值是
触发
。
getter 方法在获取值时
触发
。
三、watch:
虽然
计算属性
在大多数情况下是非常适合的,但是在有些情况下我们需要自定义一个watcher,在数据变化时来执行异步操作,这时watch是非常有用的。
一、
计算属性
?什么东东??
<div id="example">
{{ message.split('').reverse().join('') }}
&a
com
put
ed
本质是一个惰性求值的观察者。
com
put
ed
内部实现了一个惰性的 watcher,也就是
com
put
ed
watcher,
com
put
ed
watcher 不会立刻求值,同时持有一个 dep 实例。
其内部通过 this.dirty 属性标记
计算属性
是否需要
重新
求值。
当
com
put
ed
的依赖状态发生改变时,就会通知这个惰性的 watcher,
com
put
ed
watcher 通过 this.dep.subs.length 判断有没有订阅者,
有的话,会
重新
计算
,然后对比新旧值
小程序iOS Promise不支持finally语法 TypeError: undefined is not a function .finally is not a function
wen_rc: