vue 的响应式框架 (1.0)

vue 的响应式框架 (1.0)

思路:属性发生变化时,调用依赖这些属性的函数

一、实现的过程需要解决以下一些问题

  • 1.如何追踪属性发生了变化
  • 2.如何知道该属性被哪些依赖使用
  • 3.如何执行依赖的函数
  • 4.如何避免重复执行依赖的函数

二、基础知识

object.defineProperty(obj, prop, descriptor)方法介绍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//定义一个对象
var obj = {
name: '张三',
age : 20
}

object.defineProperty(obj,name){
get:function(){
console.log('有人读取了name属性')
return obj.name
}
set function(val){ //obj中的name发生那个变化后,会调用set函数。因此可在这里调用其依赖函数
obj.name = val
console.log('有个家伙在给name属性赋值')
}
}

去重

1
2
3
4
5
6
7
//方法一:Set集合,可以判断,如果当前的值和之前的值相同,则不执行依赖函数
let funcs = new Set()
//方法二:ES6中的includes方法,判断当前的值是否在数组中,如果在,则不执行依赖函数
let funcs = []
if (!funcs.includes(func)) {
funcs.push(func)
}

三、难点

此时我们已经解决了问题1和问题4,也知道了依赖函数应该在set中执行。那么如何知道属性被哪些依赖使用呢?

1
2
3
4
5
// 不直接运行函数,而是使用定义一个全局变量,这样只要使用这个统一变量的名称运行函数,就能拿到函数了
window.__func = func1
func1()
window.__func = null
//这样只需在get中添加window.__func到数组即可

四、实现

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
//首先新建一个js,在这个新的js中实现上述代码
//定义一个观察者,监视对象的属性
function Observer(obj) {
for (const key in obj){
let intervalValue = obj[key]
let observers = new Set() //用来保存相关依赖
//使用Object.defineProperty()方法,给obj的key属性添加get和set方法
defineProperty(obj, key, obj[key]){
get: function(){
if (window.__func){ //存在说明有函数在运行,是哪个函数呢,那个函数名使用window.__func可以访问到
observers.add(window.__func)
}
return intervalValue
},
set: function(val){
console.log('有人修改了' + key + '属性,我要去通知我的订阅者了')
obj[key] = val
//通知所有的订阅者,重新运行
observers.forEach(observer => observer())
}
}
}
}

// 定义一个统一执行函数的函数
function autoRun(fn){
window.__func = fn
fn()
window.__func = null
}

//函数调用时用autoRun不要直接运行
autoRun(func1())
autoRun(func2())