响应式原理

1:响应式函数的封装

 1 //封装一个函数的响应式
 2 //用数组来保存需要响应的函数
 3 const reactiveFns = []
 4     //在watchFn里面的函数都会被监视
 5 function watchFn(fn) {
 6     reactiveFns.push(fn)
 7 }
 8 //对象的响应式
 9 const obj = {
10     name: 'haha',
11     age: 20
12 }
13 watchFn(function() {
14     let newName = obj.name
15     console.log('哈哈哈哈哈', obj.name);
16 })
17 watchFn(function() {
18     console.log(obj.name, 'demo function----');
19 })
20 
21 function bar() {
22     console.log('普通的函数');
23 
24 }
25 obj.name = 'tyy'
26     //手动让响应式执行
27 reactiveFns.forEach(fn => fn())

 

 2:响应式依赖的收集,如果只是把需要响应的放在一个类里面是补够的,每个属性的变化都应该有对应的响应式函数----这里可以设计一个类

 1 //创建一个类
 2 class Depend {
 3     constructor() {
 4         this.reactiveFns = []
 5     }
 6     addDepend(reactiveFn) {
 7         this.reactiveFns.push(reactiveFn)
 8     }
 9     notify() {
10         this.reactiveFns.forEach(fn => fn())
11     }
12 }
13 //封装一个响应式函数
14 const depend = new Depend()
15 
16 function watchFn(fn) {
17     depend.addDepend(fn)
18 }
19 //对象的响应式
20 const obj = {
21     name: 'haha',
22     age: 20
23 }
24 watchFn(function() {
25     let newName = obj.name
26     console.log('哈哈哈哈哈', obj.name);
27 })
28 watchFn(function() {
29     console.log(obj.name, 'demo function----');
30 })
31 
32 
33 obj.name = 'tyy'
34 depend.notify()

和第一个一样的结果

3:自动监听对象变化 采用Proxy和Reflect自动监听属性变化

 1 //创建一个类
 2 class Depend {
 3     constructor() {
 4         this.reactiveFns = []
 5     }
 6     addDepend(reactiveFn) {
 7         this.reactiveFns.push(reactiveFn)
 8     }
 9     notify() {
10         this.reactiveFns.forEach(fn => fn())
11     }
12 }
13 //封装一个响应式函数
14 const depend = new Depend()
15 
16 function watchFn(fn) {
17     depend.addDepend(fn)
18 }
19 //对象的响应式
20 const obj = {
21         name: 'haha',
22         age: 20
23     }
24     //监听属性的变化 Proxy/Reflect
25 const objProxy = new Proxy(obj, {
26     get: function(target, key, receiver) {
27         return Reflect.get(target, key, receiver)
28     },
29     set: function(target, key, newValue, receiver) {
30         Reflect.set(target, key, newValue, receiver)
31         depend.notify()
32     }
33 })
34 
35 watchFn(function() {
36     console.log('哈哈哈哈哈', objProxy.name);
37 })
38 watchFn(function() {
39     console.log(objProxy.name, 'demo function----');
40 })
41 watchFn(function() {
42     console.log(objProxy.age, 'age变化需要执行的');
43 })
44 
45 objProxy.name = 'tyy'
46 objProxy.age = 18

 

 由图片可以看出来这个无论是那个属性发生变化,响应式的函数都会执行

4:依赖收集的管理

采用这种数据结构,利用map和weakMap来给每个属性构造depend

 

 

 1 //创建一个类
 2 class Depend {
 3     constructor() {
 4         this.reactiveFns = []
 5     }
 6     addDepend(reactiveFn) {
 7         this.reactiveFns.push(reactiveFn)
 8     }
 9     notify() {
10         this.reactiveFns.forEach(fn => fn())
11     }
12 }
13 //封装一个depend 函数
14 const depend = new Depend()
15 function watchFn(fn) {
16     depend.addDepend(fn)
17 }
18 //封装一个获取depend函数
19 const targetMap = new WeakMap()
20 
21 function getDepend(target, key) {
22     //通过target获取map对象
23     let map = targetMap.get(target)
24     if (!map) {
25         map = new Map()
26         targetMap.set(target, map)
27     }
28     let depend = map.get(key)
29     if (!depend) {
30         depend = new Depend()
31         map.set(key, depend)
32     }
33     return depend
34 }
35 
36 
37 //对象的响应式
38 const obj = {
39         name: 'haha',
40         age: 20
41     }
42     //监听属性的变化 Proxy/Reflect
43 const objProxy = new Proxy(obj, {
44     get: function(target, key, receiver) {
45         return Reflect.get(target, key, receiver)
46     },
47     set: function(target, key, newValue, receiver) {
48         Reflect.set(target, key, newValue, receiver)
49         const depend = getDepend(target, key)
50         depend.notify()
51     }
52 })
53 
54 watchFn(function() {
55     console.log('哈哈哈哈哈', objProxy.name);
56 })
57 watchFn(function() {
58     console.log(objProxy.name, 'demo function----');
59 })
60 watchFn(function() {
61     console.log(objProxy.age, 'age变化需要执行的');
62 })

5:正确的函数依赖收集

上面我们都是采用watchFn来响应的,我们不能实现name响应name的函数,我们需要获取相应的depend 在get的时候把正确函数放在正确的依赖里面

 1 //创建一个类
 2 class Depend {
 3     constructor() {
 4         this.reactiveFns = []
 5     }
 6     addDepend(reactiveFn) {
 7         this.reactiveFns.push(reactiveFn)
 8     }
 9     notify() {
10         this.reactiveFns.forEach(fn => fn())
11     }
12 }
13 //封装一个depend 函数
14 const depend = new Depend()
15 let globalfn = null
16 
17 function watchFn(fn) {
18     globalfn = fn
19     fn()
20     globalfn = null
21 }
22 //封装一个获取depend函数
23 const targetMap = new WeakMap()
24 
25 function getDepend(target, key) {
26     //通过target获取map对象
27     let map = targetMap.get(target)
28     if (!map) {
29         map = new Map()
30         targetMap.set(target, map)
31     }
32     let depend = map.get(key)
33     if (!depend) {
34         depend = new Depend()
35         map.set(key, depend)
36     }
37     return depend
38 }
39 
40 
41 //对象的响应式
42 const obj = {
43         name: 'haha',
44         age: 20
45     }
46     //监听属性的变化 Proxy/Reflect
47 const objProxy = new Proxy(obj, {
48     get: function(target, key, receiver) {
49         const depend = getDepend(target, key)
50         depend.addDepend(globalfn)
51         return Reflect.get(target, key, receiver)
52 
53     },
54     set: function(target, key, newValue, receiver) {
55         Reflect.set(target, key, newValue, receiver)
56         const depend = getDepend(target, key)
57         depend.notify()
58     }
59 })
60 
61 watchFn(function() {
62     console.log('哈哈哈哈哈', objProxy.name);
63 })
64 watchFn(function() {
65     console.log(objProxy.name, 'demo function----');
66 })
67 watchFn(function() {
68     console.log(objProxy.age, 'age变化需要执行的');
69 })
70 console.log('name改变啦---------------------------');
71 objProxy.name = 'tyy'
72 console.log('age改变啦--------------------------');
73 objProxy.age = 20

 

 6:depend的优化

使用set保存依赖函数 方式一个watchfn 里面多次调用同一个属性添加多次depend 注意,set中是add方法

 1 //创建一个类
 2 class Depend {
 3     constructor() {
 4         //防止adddepend方法重复
 5         this.reactiveFns = new Set()
 6     }
 7 
 8     //让get里面更加简单
 9     depend() {
10         if (globalfn) {
11             this.reactiveFns.add(globalfn)
12         }
13     }
14     notify() {
15         this.reactiveFns.forEach(fn => fn())
16     }
17 }
18 //封装一个depend 函数
19 const depend = new Depend()
20 let globalfn = null
21 
22 function watchFn(fn) {
23     globalfn = fn
24     fn()
25     globalfn = null
26 }
27 //封装一个获取depend函数
28 const targetMap = new WeakMap()
29 
30 function getDepend(target, key) {
31     //通过target获取map对象
32     let map = targetMap.get(target)
33     if (!map) {
34         map = new Map()
35         targetMap.set(target, map)
36     }
37     let depend = map.get(key)
38     if (!depend) {
39         depend = new Depend()
40         map.set(key, depend)
41     }
42     return depend
43 }
44 
45 
46 //对象的响应式
47 const obj = {
48         name: 'haha',
49         age: 20
50     }
51     //监听属性的变化 Proxy/Reflect
52 const objProxy = new Proxy(obj, {
53         get: function(target, key, receiver) {
54             const depend = getDepend(target, key)
55             depend.depend()
56             return Reflect.get(target, key, receiver)
57 
58         },
59         set: function(target, key, newValue, receiver) {
60             Reflect.set(target, key, newValue, receiver)
61             const depend = getDepend(target, key)
62             depend.notify()
63         }
64     })
65     //watchFn
66 
67 watchFn(() => {
68     console.log(objProxy.name, '----------'); //get一次 adddepend就添加一次
69     console.log(objProxy.name, '++++++++++');
70 })
71 console.log('name改变啦---------------------------');
72 objProxy.name = 'tyy'

 

 7:对象的响应式操作vue2和vue3--------自动化对象响应 封装一个函数----把函数变成响应式函数

Vue3

 1 //创建一个类
 2 class Depend {
 3     constructor() {
 4         //防止adddepend方法重复
 5         this.reactiveFns = new Set()
 6     }
 7 
 8     //让get里面更加简单
 9     depend() {
10         if (globalfn) {
11             this.reactiveFns.add(globalfn)
12         }
13     }
14     notify() {
15         this.reactiveFns.forEach(fn => fn())
16     }
17 }
18 //封装一个depend 函数
19 const depend = new Depend()
20 let globalfn = null
21 
22 function watchFn(fn) {
23     globalfn = fn
24     fn()
25     globalfn = null
26 }
27 //封装一个获取depend函数
28 const targetMap = new WeakMap()
29 
30 function getDepend(target, key) {
31     //通过target获取map对象
32     let map = targetMap.get(target)
33     if (!map) {
34         map = new Map()
35         targetMap.set(target, map)
36     }
37     let depend = map.get(key)
38     if (!depend) {
39         depend = new Depend()
40         map.set(key, depend)
41     }
42     return depend
43 }
44 
45 
46 //对象的响应式
47 const obj1 = {
48     name: 'haha',
49     age: 20
50 }
51 const objProxy = reactive(obj1)
52     //监听属性的变化 Proxy/Reflect 封装成把一个对象变成响应式的函数
53 function reactive(obj) {
54     return new Proxy(obj, {
55         get: function(target, key, receiver) {
56             const depend = getDepend(target, key)
57             depend.depend()
58             return Reflect.get(target, key, receiver)
59 
60         },
61         set: function(target, key, newValue, receiver) {
62             Reflect.set(target, key, newValue, receiver)
63             const depend = getDepend(target, key)
64             depend.notify()
65         }
66     })
67 }
68 //watchFn
69 
70 watchFn(() => {
71     console.log(objProxy.name, '----------'); //get一次 adddepend就添加一次
72     console.log(objProxy.name, '++++++++++');
73 })
74 const obj2 = reactive({
75     mood: 'unhappy'
76 })
77 watchFn(() => {
78     console.log(obj2.mood, 'obj2对象的响应式');
79 })
80 console.log('name改变啦---------------------------');
81 objProxy.name = 'tyy'
82 console.log('mood改变啦---------------------------');
83 obj2.mood = 'happy'

 

 Vue2

 1 //创建一个类
 2 class Depend {
 3     constructor() {
 4         //防止adddepend方法重复
 5         this.reactiveFns = new Set()
 6     }
 7 
 8     //让get里面更加简单
 9     depend() {
10         if (globalfn) {
11             this.reactiveFns.add(globalfn)
12         }
13     }
14     notify() {
15         this.reactiveFns.forEach(fn => fn())
16     }
17 }
18 //封装一个depend 函数
19 const depend = new Depend()
20 let globalfn = null
21 
22 function watchFn(fn) {
23     globalfn = fn
24     fn()
25     globalfn = null
26 }
27 //封装一个获取depend函数
28 const targetMap = new WeakMap()
29 
30 function getDepend(target, key) {
31     //通过target获取map对象
32     let map = targetMap.get(target)
33     if (!map) {
34         map = new Map()
35         targetMap.set(target, map)
36     }
37     let depend = map.get(key)
38     if (!depend) {
39         depend = new Depend()
40         map.set(key, depend)
41     }
42     return depend
43 }
44 
45 
46 //对象的响应式
47 const obj1 = {
48     name: 'haha',
49     age: 20
50 }
51 const objProxy = reactive(obj1)
52     //监听属性的变化 Proxy/Reflect 封装成把一个对象变成响应式的函数
53 function reactive(obj) {
54     Object.keys(obj).forEach(key => {
55         let value = obj[key]
56         Object.defineProperty(obj, key, {
57             get() {
58                 const dep = getDepend(obj, key)
59                 dep.depend()
60                 return value
61 
62             },
63             set(newValue) {
64                 const dep = getDepend(obj, key)
65                 value = newValue
66                 dep.notify()
67             }
68         })
69     })
70     return obj
71 }
72 //watchFn
73 
74 watchFn(() => {
75     console.log(objProxy.name, '----------'); //get一次 adddepend就添加一次
76     console.log(objProxy.name, '++++++++++');
77 })
78 const obj2 = reactive({
79     mood: 'unhappy'
80 })
81 watchFn(() => {
82     console.log(obj2.mood, 'obj2对象的响应式');
83 })
84 console.log('name改变啦---------------------------');
85 objProxy.name = 'tyy'
86 console.log('mood改变啦---------------------------');
87 obj2.mood = 'happy'

和Vue3一样的结果

 

posted @ 2022-03-30 19:55  沁霓  阅读(80)  评论(0)    收藏  举报