手把手实现简易响应式设计(Watcher-Observer-Dependency)

图解

img

Owd

  1. 拥有一份数据 _data
  2. 一个 watch 函数
1
2
3
4
5
6
7
8
9
10
11
class Owd {
constructor(data) {
this._data = data

// TODO reactive
}

watch(key, fn) {
// TODO
}
}

Observer

  1. _data 变成 reactive
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
class Owd {
constructor(data) {
this._data = data

// reactive
observe(this._data)
}

watch(key, fn) {
// TODO
}
}

class Observer {
constructor(data) {
Object.keys(data).forEach(
key => reactive(data, key, data[key])
)
}
}

function reactive(obj, key, val) {
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function() {
console.log('getter: ', val)
return val
},

set: function(newVal) {
let oldVal = val

val = newVal

console.log('setter: ', oldVal, newVal)
}
})
}

function observe(data) {
// 这样可以在这里增加一些额外的处理 ...

new Observer(data)
}

const owd = new Owd({
count: 0
})

owd.watch('count', () => console.log('owd count: ' + owd._data.count))

owd._data.count++

+RESULTS:

getter:  0
setter:  0 1
undefined

owd._data.count++ 触发了 setter 输出 setter: 0 1

Watcher

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
jG// 1. Owd
class Owd {
constructor(data) {
this._data = data

// reactive
observe(this._data)
}

watch(key, fn) {
// 收集当前的 owd 实例和要监听的 key - fn
new Watcher(this, key, fn)
}
}

// 2. Observer
class Observer {
constructor(data) {
Object.keys(data).forEach(
key => reactive(data, key, data[key])
)
}
}

// 3. Watcher 收集当前 attr - fn
class Watcher {
constructor(owd, attr, fn) {
this.attr = attr
this.fn = fn

owd._data[attr]
}
}

function reactive(obj, key, val) {
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function() {
console.log('getter: ', val)
return val
},

set: function(newVal) {
let oldVal = val

val = newVal

console.log('setter: ', oldVal, newVal)
}
})
}

function observe(data) {
// 这样可以在这里增加一些额外的处理 ...

new Observer(data)
}

const owd = new Owd({
count: 0
})

owd.watch('count', () => console.log('owd count: ' + owd._data.count))

owd._data.count++

Dep

在这之前我们有三个类:

  1. Owd
  2. Observer 观察 owd._data 的类,让其属性变成 reactive
  3. Watcher 收集 owd._dataattr 和其订阅者 fn

这部分的 Dep 其很关键的作用,因为它是链接 Owd, Observer, Watcher 的关键。

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
87
88
89
90
91
// 1. Owd
class Owd {
constructor(data) {
this._data = data

// reactive
observe(this._data)
}

watch(key, fn) {
// 收集当前的 owd 实例和要监听的 key - fn
new Watcher(this, key, fn)
}
}

// 2. Observer
class Observer {
constructor(data) {
Object.keys(data).forEach(
key => reactive(data, key, data[key])
)
}
}

// 3. Watcher 收集当前 attr - fn
class Watcher {
constructor(owd, attr, fn) {
this.attr = attr
this.fn = fn

Dep.target = this

owd._data[attr]
}
}

// 4. Dep 收集 Watcher
class Dep {
constructor() {
this.subs = []
}

depend() {
if (this.subs.indexOf(Dep.target) > -1) return
this.subs.push(Dep.target)
}

notify() {
this.subs.forEach(
watcher => watcher.fn()
)
}
}

Dep.target = null

function reactive(obj, key, val) {

const dep = new Dep()

Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function() {
dep.depend()
return val
},

set: function(newVal) {
let oldVal = val

val = newVal
dep.notify()
}
})
}

function observe(data) {
// 这样可以在这里增加一些额外的处理 ...

new Observer(data)
}

const owd = new Owd({
count: 0
})

owd.watch('count', () => console.log('owd count 1: ' + owd._data.count))
owd.watch('count', () => console.log('owd count 2: ' + owd._data.count))

owd._data.count++

本文标题:手把手实现简易响应式设计(Watcher-Observer-Dependency)

文章作者:ZhiCheng Lee

发布时间:2019年04月22日 - 16:01:45

最后更新:2019年06月16日 - 20:28:12

原始链接:http://blog.gcl666.com/2019/04/22/watcher_observer_dependent/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

0%