基础依赖收集和触发,就这么简单

概述

Vue源码部分讲的依赖收集和触发比较复杂,不容易理解。今天我把它最简化讲出来。如果你有收获,请给小弟一个赞。

前期准备

  1. 声明一个Map做储蓄;
  2. current用来传递数据;
  3. data数据备用;
const map = new Map();
let current = null;
const data = {
    name: 'madapao',
    age: 18,
    sex: '男',
}
复制代码

创建一个Watcher类

deps数组收集依赖,add方法添加依赖。

class Watcher {
    constructor() {
        this.deps = [];
    }
    add(dep) {
        this.deps.push(dep)
    }
}
复制代码

收集和触发

对data中的数据进行劫持:

  • get:判断map中有没有这个key,如果没有,就新建一个watcher,把current(current是什么等访问的时候就知道了)加进行watcher的deps中,每个key在map中对应一个watcher。如果已经有了,直接拿出来wathcer,把current加进行watcher的deps中。
  • set:拿出map中key对应的watcher,把它deps中的方法全部执行一次。
Object.keys(data).forEach(key => {
    Object.defineProperty(data, key, {
        get() {
            if (map.has(key)) {
                const watcher = map.get(key);
                watcher.add(current);
                map.set(key, watcher)
            } else {
                const watcher = new Watcher();
                watcher.add(current);
                deps.set(key, watcher);
            }
        },
        set() {
            if (map.has(key)) {
                map.get(key).deps.forEach(fn => fn())
            }
        }
    })
})
复制代码

使用

在执行getAgeName方法,暂时把getAgeName赋值给current,使用data中数据key时。就会触发key的get。把getAgeName放进key对应watcher的deps中。

当修改key的值时,就会触发key对应watcher收集到的所有方法。

function getAgeName() {
    current = getAgeName;
    console.log('getAgeName执行了')
    return `${data.name}'今年'${data.age}岁。`
}
function getSexName() {
    current = getSexName;
    console.log('getSexName执行了')
    return `${data.name}'是一个'${data.sex}人。`
}

getAgeName();
getSexName();
data.name = 'mahaha';
复制代码

全部代码

const deps = new Map();
let current = null;
class Watcher {
    constructor() {
        this.deps = [];
    }
    add(dep) {
        this.deps.push(dep)
    }
}
const data = {
    name: 'madapao',
    age: 18,
    sex: '男',
}
Object.keys(data).forEach(key => {
    Object.defineProperty(data, key, {
        get() {
            if (deps.has(key)) {
                const watcher = deps.get(key);
                watcher.add(current);
                deps.set(key, watcher)
            } else {
                const watcher = new Watcher();
                watcher.add(current);
                deps.set(key, watcher);
            }
        },
        set() {
            if (deps.has(key)) {
                deps.get(key).deps.forEach(fn => fn())
            }
        }
    })
})

function getAgeName() {
    current = getAgeName;
    console.log('getAgeName执行了')
    return `${data.name}'今年'${data.age}岁。`
}
function getSexName() {
    current = getSexName;
    console.log('getSexName执行了')
    return `${data.name}'是一个'${data.sex}人。`
}

getAgeName();
getSexName();
data.name = 'mahaha';
复制代码

猜你喜欢

转载自juejin.im/post/7039956123033534494