Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

理解vue响应式原理(2)--computed #14

Open
conan1992 opened this issue Jun 13, 2020 · 0 comments
Open

理解vue响应式原理(2)--computed #14

conan1992 opened this issue Jun 13, 2020 · 0 comments

Comments

@conan1992
Copy link
Owner

vue计算属性 computed

computed传入的其实还是一个函数;

Watcher的本质,其实就是存储了一个需要在特定时机触发的函数,在Vue内部,每个computed属性也有自己的一个对应的watcher实例,下文中叫它computedWatcher
computedWatcher的特点:

  • 有自己的dep来存储watcher
  • 惰性求值,初始化的时候先不去运行getter。
    实现本质:computed在读取属性值时,此时的Dep.target是正在运行的渲染函数的watcher
// 渲染函数watcher
new Watcher(() => {
  document.getElementById('app').innerHTML = `
    computed: 1 + number 是 ${computedNumber.value}
  `
})

因此,我们实现的过程是这样的

  • computed在读取属性值时,Dep.target是正在运行的渲染函数的watcher
  • 先把当前Dep.target存储到computedWatcher的dep小箩筐里
  • 再把comoutedWatcher赋值给局Dep.target;
  • 开始计算,计算值的时候又会读取响应式属性,这时Dep.target也就是computedWatcher被添加到响应式属性的dep里(也就是data.number的dep里),就这样层层嵌套;

当data.number更新时,触发computedWatcher.update;computedWatcher的dep里装着渲染watcher,所以只需要触发 this.dep.notify(),就会触发渲染watcher的update方法,从而更新视图。

更新的路径是这样的 data.number = 5 -> computedWatcher -> 渲染watcher -> 更新视图

//computed.js
import Watcher from "./watcher"

export default function computed( getter ){
    let def = {};
    const computedWatcher = new Watcher( getter, {computed: true})
    Object.defineProperty(def, "value", {
        get(){
            computedWatcher.dep.depend();
            return computedWatcher.get();
        }
    })
    return def;
}
import Dep, {pushTarget, popTarget } from "./dep"

export default class Watcher {
    constructor( getter, options = {} ){
        let {computed, watch, callback} = options;
        this.getter = getter;
        this.computed = computed;
        this.watch = watch;
        this.callback = callback;
        this.value = undefined;
        if(computed){
            this.dep = new Dep();
        }else{
            this.get();
        }
        
    }
    depend(){
        this.dep.depend()
    }
    get(){
        pushTarget(this);
        this.value = this.getter();
        popTarget();
        return this.value
    }
    update(){
        if(this.computed){
            this.get();
            this.dep.notify();
        }else{
            this.get();
        }
        
    }
}

参考:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant