实现简易观察者模式和watch

# 实现简易观察者模式和watch

实现 ob 和 watch 方法,希望当方法传入 watch 函数时会执行一次,之后每次修改 data 上的属性时,会触发对应的 console

const data = ob({ count: 0, foo: 'test' });

watch(() => {
    console.log('watch-count', data.count);
});
watch(() => {
    console.log('watch-foo', data.foo);
});

data.count += 1;
console.log('showcount', data.count);
delete data.count;
data.foo = 'test2';
1
2
3
4
5
6
7
8
9
10
11
12
13

实现: 主要是借助 Proxy/Reflect 进行检测代理, 一旦检测对象发生改变, 就触发watch的钩子函数

点击查看代码










 






 












 
























































const handlers = new Map()

function ob(data) {
  return new Proxy(data, {
    get(target, key, receiver) {
      return Reflect.get(target, key, receiver)
    },
    set(target, key, value, receiver) {
      const result = Reflect.set(target, key, value, receiver)
      if (handlers.has(key)) {
        handlers.get(key).forEach(handler => handler(value))
      }
      return result
    },
    deleteProperty(target, key) {
      const result = Reflect.deleteProperty(target, key)
      if (handlers.has(key)) {
        handlers.get(key).forEach(handler => handler(undefined))
      }
      return result
    }
  })
}

function watch(handler) {
  const observedKeys = new Set()
  const observe = (key, handler) => {
    if (!handlers.has(key)) {
      handlers.set(key, new Set())
    }
    handlers.get(key).add(handler)
  }

  const unobserve = (key, handler) => {
    if (handlers.has(key)) {
      handlers.get(key).delete(handler)
    }
  }

  const observeAll = () => {
    Object.keys(data).forEach(key => {
      observe(key, handler)
      observedKeys.add(key)
    })
  }

  const unobserveAll = () => {
    observedKeys.forEach(key => {
      unobserve(key, handler)
    })

    observedKeys.clear()
  }

  observeAll()

  return {
    observe,
    unobserve,
    observeAll,
    unobserveAll,
  }
}

const data = ob({ count: 0, foo: 'test' })

watch(() => {
  console.log('watch-count', data.count);
});

watch(() => {
  console.log('watch-foo', data.foo);
});

data.count += 1;
console.log('showcount', data.count);
delete data.count;
data.foo = 'test2';

// watch-count 1
// watch-foo test
// showcount 1
// watch-count undefined
// watch-foo test
// watch-count undefined
// watch-foo test2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86

# 参考资料