点击可打开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: