# Heading
源码版本vue:2.6.10
参考链接:https://segmentfault.com/a/1190000018659584 # 简易双向绑定
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input class="inp-text" type="text">
<div class="text-box"></div>
<script type='module'>
let obj = {};
Object.defineProperty(obj, 'name', {
set: function (newValue) {
console.log('setter', newValue)
document.querySelector('.text-box').innerHTML = `${newValue}`.split('').reverse().join('');
document.querySelector('.inp-text').value = newValue;
},
get: function () {
console.log('getter')
}
})
document.querySelector('.inp-text').addEventListener('keyup', function (e) {
obj.name = e.target.value;
}, false);
globalThis.obj = obj
</script>
</body>
</html>
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
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
# 核心思想
核心思想:Object.defineProperty(obj, key, {set, get})
Observer类,收集依赖&触发更新
/**
* Observer class that is attached to each observed
* object. Once attached, the observer converts the target
* object's property keys into getter/setters that
* collect dependencies and dispatch updates.
*/
export class Observer {
value: any;
dep: Dep;
vmCount: number; // number of vms that have this object as root $data
constructor (value: any) {
this.value = value
this.dep = new Dep()
this.vmCount = 0
def(value, '__ob__', this)
// def如下
// Object.defineProperty(value, '__ob__', {
// value: this,
// enumerable: !!enumerable,
// writable: true,
// configurable: true
// })
if (Array.isArray(value)) {
if (hasProto) {
//通过原型链添加方法
protoAugment(value, arrayMethods)
} else {
//通过 def定义隐藏属性 添加方法
copyAugment(value, arrayMethods, arrayKeys)
}
this.observeArray(value)
} else {
this.walk(value)
}
}
/**
* Walk through all properties and convert them into
* getter/setters. This method should only be called when
* value type is Object.
*/
//对于对象的每一个属性,遍历转换成getter/setters
walk (obj: Object) {
const keys = Object.keys(obj)
for (let i = 0; i < keys.length; i++) {
defineReactive(obj, keys[i])
}
}
/**
* Observe a list of Array items.
*/
//遍历数组,调用new Observer(value)
observeArray (items: Array<any>) {
for (let i = 0, l = items.length; i < l; i++) {
observe(items[i])
}
}
}
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
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
::: 定义响应式属性
/**
* Define a reactive property on an Object.
*/
export function defineReactive (
obj: Object,
key: string,
val: any,
customSetter?: ?Function,
shallow?: boolean //浅的
) {
const dep = new Dep()
const property = Object.getOwnPropertyDescriptor(obj, key)
if (property && property.configurable === false) {
return
}
// cater for pre-defined getter/setters
const getter = property && property.get
const setter = property && property.set
if ((!getter || setter) && arguments.length === 2) {
val = obj[key]
}
let childOb = !shallow && observe(val)
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
const value = getter ? getter.call(obj) : val
if (Dep.target) {//target(Watcher) 目标watcher,同一时间只能有一个watcher被计算
dep.depend()
//收集依赖 Dep.target.addDep(this)
// this.newDepIds.add(id) Array<Dep>
// this.newDeps.push(dep) SimpleSet
if (childOb) {
childOb.dep.depend()
if (Array.isArray(value)) {
/**
* Collect dependencies on array elements when the array is touched, since
* we cannot intercept array element access like property getters.
当数组被访问时收集依赖,因为我们不能像对象一样拦截数组 ??
*/
dependArray(value)
}
}
}
return value
},
set: function reactiveSetter (newVal) {
const value = getter ? getter.call(obj) : val
/* eslint-disable no-self-compare */
if (newVal === value || (newVal !== newVal && value !== value)) {
//这是为了判断NaN吧……
return
}
/* eslint-enable no-self-compare */
if (process.env.NODE_ENV !== 'production' && customSetter) {
customSetter()
}
// #7981: for accessor properties without setter
if (getter && !setter) return
if (setter) {
setter.call(obj, newVal)
} else {
val = newVal
}
childOb = !shallow && observe(newVal)//如果是深
dep.notify()//通知订阅者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
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
:::
::: 当一个属性的setter触发时 notify通知订阅者
notify () {
// stabilize the subscriber list first
const subs = this.subs.slice()//订阅者
if (process.env.NODE_ENV !== 'production' && !config.async) {
// subs aren't sorted in scheduler if not running async
// we need to sort them now to make sure they fire in correct
// order
subs.sort((a, b) => a.id - b.id)
}
for (let i = 0, l = subs.length; i < l; i++) {
subs[i].update()
//触发Watcher的run方法执行job
// update () {
// /* istanbul ignore else */
// if (this.lazy) {
// this.dirty = true
// } else if (this.sync) {
// this.run()
// } else {
// queueWatcher(this)
// }
// }
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
:::