简单实现 一

问题分析 effect 函数只有一个

  1. const bucket = new Set();
  2. const data = {text: "hello world vue"};
  3. const obj = new Proxy(data, {
  4. get(target, key) {
  5. bucket.add(effect);
  6. return target[key];
  7. },
  8. set(target, key, newVal) {
  9. target[key] = newVal;
  10. bucket.forEach(fn => fn());
  11. return true;
  12. }
  13. })
  14. function effect() {
  15. document.body.innerText = obj.text;
  16. }
  17. effect();
  18. setTimeout(() => {
  19. obj.text = "hello vue3";
  20. })

简单实现 二

关系分析

  1. 一个副作用函数,读取一个对象的一个属性值
  2. target
  3. └── key
  4. └── effectFn
  5. 如果有两个副作用函数,读取同一个对象的一个属性值
  6. target
  7. └── key
  8. ├── effectFn1
  9. └── effectFn2
  10. 在不同的副作用函数中,读取了同一个对象的两个属性值
  11. target
  12. ├── key1
  13. └── effectFn
  14. └── key2
  15. └── effectFn
  16. 在不同的副作用函数中读取了两个不同对象的不同属性
  17. target1
  18. └── key1
  19. └── effectFn1
  20. target2
  21. └── key2
  22. └── effectFn2

问题分析,没有销毁能力

  1. const bucket = new Set();
  2. const data = {text: "hello world vue"};
  3. const obj = new Proxy(data, {
  4. get(target, key) {
  5. if (activeEffect) {
  6. bucket.add(activeEffect);
  7. }
  8. return target[key];
  9. },
  10. set(target, key, newVal) {
  11. target[key] = newVal;
  12. bucket.forEach(fn => fn());
  13. return true;
  14. }
  15. })
  16. let activeEffect;
  17. function effect(fn) {
  18. activeEffect = fn;
  19. fn();
  20. }
  21. effect(
  22. // 一个匿名的副作用函数
  23. () => {
  24. document.body.innerText = obj.text;
  25. }
  26. );
  27. setTimeout(() => {
  28. obj.text = "hello vue3";
  29. })

简单实现 三

使用WeakMap Map Set 维护 bucket

为什么要使用 weakMap

  1. var weakMap = new WeakMap();
  2. var map = new Map();
  3. (() => {
  4. const foo = {foo: 1};
  5. const bar = {bar: 2};
  6. map.set(foo, 1);
  7. weakMap.set(bar, 2);
  8. })()

解决了,没有销毁能力的问题

  1. const bucket = new WeakMap();
  2. const data = {text: "hello world vue"};
  3. const obj = new Proxy(data, {
  4. get(target, key) {
  5. if (!activeEffect) {
  6. return target[key];
  7. }
  8. let depsMap = bucket.get(target);
  9. if (!depsMap) {
  10. bucket.set(target, (depsMap = new Map()));
  11. }
  12. let deps = depsMap.get(key);
  13. if (!deps) {
  14. depsMap.set(key, (deps = new Set()));
  15. }
  16. deps.add(activeEffect);
  17. return target[key];
  18. },
  19. set(target, key, newVal) {
  20. target[key] = newVal;
  21. const depsMap = bucket.get(target);
  22. if (!depsMap) return;
  23. const effects = depsMap.get(key);
  24. effects && effects.forEach(fn => fn());
  25. return true;
  26. }
  27. })
  28. let activeEffect;
  29. function effect(fn) {
  30. activeEffect = fn;
  31. fn();
  32. }
  33. effect(
  34. // 一个匿名的副作用函数
  35. () => {
  36. document.body.innerText = obj.text;
  37. }
  38. );
  39. setTimeout(() => {
  40. obj.text = "hello vue3";
  41. })

简单实现 四

  1. const bucket = new WeakMap();
  2. const data = {text: "hello world vue"};
  3. const track = (target, key) => { // [træk] 跟踪
  4. if (!activeEffect) {
  5. return
  6. }
  7. let depsMap = bucket.get(target);
  8. if (!depsMap) {
  9. bucket.set(target, (depsMap = new Map()));
  10. }
  11. let deps = depsMap.get(key);
  12. if (!deps) {
  13. depsMap.set(key, (deps = new Set()));
  14. }
  15. deps.add(activeEffect);
  16. }
  17. const trigger = (target, key) => {
  18. const depsMap = bucket.get(target);
  19. if (!depsMap) return;
  20. const effects = depsMap.get(key);
  21. effects && effects.forEach(fn => fn());
  22. }
  23. const obj = new Proxy(data, {
  24. get(target, key) {
  25. track(target, key);
  26. return target[key];
  27. },
  28. set(target, key, newVal) {
  29. target[key] = newVal;
  30. trigger(target, key);
  31. return true;
  32. }
  33. })
  34. let activeEffect;
  35. function effect(fn) {
  36. activeEffect = fn;
  37. fn();
  38. }
  39. effect(
  40. // 一个匿名的副作用函数
  41. () => {
  42. document.body.innerText = obj.text;
  43. }
  44. );
  45. setTimeout(() => {
  46. obj.text = "hello vue3";
  47. })