先把之前写过的 vue 的响应式原理里的代码略加修改搬过来

/* eslint-disable no-unused-vars */
// let x;
// let y;
// let f = n => n * 100 + 100;

let active;

let watch = function (cb) {
  active = cb;
  active();
  active = null;
};

let queue = [];
let nextTick = (cb) => Promise.resolve().then(cb);
let queueJob = (job) => {
  if (!queue.includes(job)) {
    queue.push(job);
    nextTick(flushJobs);
  }
};
let flushJobs = () => {
  let job;
  while ((job = queue.shift()) !== undefined) {
    job();
  }
};

class Dep {
  constructor() {
    this.deps = new Set();
  }
  depend() {
    if (active) {
      this.deps.add(active);
    }
  }
  notify() {
    this.deps.forEach((dep) => queueJob(dep));
  }
}

let ref = (initValue) => {
  let value = initValue;
  let dep = new Dep();

  return Object.defineProperty({}, "value", {
    get() {
      dep.depend();
      return value;
    },
    set(newValue) {
      value = newValue;
      dep.notify();
    },
  });
};

let createReactive = (target, prop, value) => {
  let dep = new Dep();

  // return new Proxy(target, {
  //   get(target, prop) {
  //     dep.depend();
  //     return Reflect.get(target, prop);
  //   },
  //   set(target, prop, value) {
  //     Reflect.set(target, prop, value);
  //     dep.notify();
  //   },
  // });

  return Object.defineProperty(target, prop, {
    get() {
      dep.depend();
      return value;
    },
    set(newValue) {
      value = newValue;
      dep.notify();
    },
  });
};

export let reactive = (obj) => {
  let dep = new Dep();

  Object.keys(obj).forEach((key) => {
    let value = obj[key];
    createReactive(obj, key, value);
  });

  return obj;
};

// let data = reacitve({
//   count: 0
// });

import { Store } from "./vuex";

let store = new Store({
  state: {
    count: 0,
  },
  mutations: {
    addCount(state, payload) {
      state.count += payload || 1;
    },
  },
  plugins: [
    (store) =>
      store.subscribe((mutation, state) => {
        console.log(mutation);
      }),
  ],
});

document.getElementById("add").addEventListener("click", function () {
  // data.count++;
  store.commit("addCount", 1);
});
let str;
watch(() => {
  str = `hello ${store.state.count}`;
  document.getElementById("app").innerText = str;
});

vuex 其实也就是在构造过程中调用了 vue 的 reactive 来包裹自己的 state 来使得 state 变为响应式的。

import { reactive } from "./myVue";

export class Store {
  constructor(options = {}) {
    let { state, mutations, plugins } = options;
    this._vm = reactive(state);
    this._mutations = mutations;

    this._subscribe = [];
    plugins.forEach((plugin) => plugin(this));
  }

  get state() {
    return this._vm;
  }

  commit(type, payload) {
    const entry = this._mutations[type];
    if (!entry) {
      return;
    }
    entry(this.state, payload);
    this._subscribe.forEach((fn) => fn({ type, payload }, this.state));
  }

  subscribe(fn) {
    if (!this._subscribe.includes(fn)) {
      this._subscribe.push(fn);
    }
  }
}