1、计算属性默认不执行
Object.defineProperty =>getter
只有在取值的时候才执行
多次取值如果依赖的值不变化就只执行一次,是缓存的原因
依赖的值变化了,需要重新执行
dirty 表示这个值是不是脏的,默认是true (取值后变为false),依赖的值变化了。 dirty:true
2、只能有get和set,或者只有get 不能没有set
const vm = new Vue({
computed: {
fullName: {
get() {
console.log("ooo");
return this.firstName + this.lastName;
},
set(newValue) {
console.log(newValue);
},
},
},
});
function initComputed(vm, computed) {
const watchers = (vm._computedWatchers = {});
for (let key in computed) {
const userDef = computed[key];
// 依赖的属性变化 就重新取值get
let getter = typeof userDef == "function" ? userDef : userDef.get;
console.log(getter);
// 每个计算属性本质就是watcher
// 将watcher和属性做一个映射
watchers[key] = new Watcher(vm, getter, () => {}, { lazy: true }); //默认不执行
// 将key定义在vm上。
defineComputed(vm, key, userDef);
}
}
function defineComputed(vm, key, userDef) {
let sharedProperty = {};
if (typeof userDef == "function") {
sharedProperty.get = userDef;
} else {
sharedProperty.get = createComputedGetter(key);
sharedProperty.set = userDef.set;
}
Object.defineProperty(vm, key, sharedProperty);
}
function createComputedGetter(key) {
return function computedGetter() {
//取计算属性的值,走的是这个函数
// 所有的计算属性,通过key可以拿到对应的watcher,这个watcher包含了getter
let watcher=this._computedWatchers[key];
// 脏就是 要调用用户的getter 不脏就是不要调用getter
if(watcher.dirty){ //根据dirty来判断是否需要重新求值
watcher.evaluate(); //脏就代表能取值,能调get方法。
}
return watcher.value;
}
}
// watch 是回调 computed是getter和setter。
// 如果是计算属性, 那么默认值lazy:true, dirty:true
function evaluate(){
this.dirty=false; //为false表示取过值了
this.value=this.get(); //用户的getter
}
// 只有get方法的时候有缓存,set修改不影响
// 在页面中直接写fullName时,fullName不会去收集渲染watcher
// firstName 是在计算属性中使用的,所以他会收集计算属性watcher 没有收集渲染watcher
// dep.subs是个数组,用来存watcher
// Dep.target只有一个watcher
/***
* 计算属性中的值应该 记录计算属性watcher 和 渲染watcher
* 因为fullName 没有dep 没有收集的功能
* Dep.target 上赋值一个渲染watcher,又将Dep.target设置为计算属性watcher
*
*/
function depend(){
let i=this.deps.length;
while(i--){
this.deps[i].depend();
}
}
/**
* 1个watcher 对应多个dep
* 属性变化 通知计算属性watcher 然后再重新渲染watcher
* fullName没有渲染watcher fullName对应的计算属性watcher
* 通过计算属性watcher 找到dep 让dep收集的是渲染watcher 因为fullName没有dep 没有收集的功能。
* 计算属性和watch 都是一个watcher
*/