1.我们要做什么
实现一个迷你库,检测一组数据的变化,当数据变化的时候,做出响应。大致像下面的使用方式:
|
|
怎么实现?
2.Object.defineProperty()
我们可以使用下面的方式定义一个对象,并给对象添加一个属性。
|
|
也可以使用Object.defineProperty()给对象添加属性,上面的代码等价于
|
|
这样定义的属性是数据属性,用来描述数据。还有另外一个访问器属性,允许你定义一对儿 getter/setter ,当你读取属性值的时候底层会调用 get 方法,当你去设置属性值的时候,底层会调用 set 方法。
这简直太美妙了,这不正是我们想要的吗?
遍历对象的属性,把对象的属性都使用 Object.defineProperty 转为 getter/setter ,这样,当我们修改一些值得时候,就会调用set方法,然后我们在set方法里面,回调通知,这样不就可以了吗?
|
|
3.保存旧值
现在我们成功的监测到数据变化并且做出响应了。但是这个响应只处理了新值,有时候我们是需要旧值的,现在我们的代码还无法传递旧值,怎么改?
|
|
4.监测数组变化
这样子看上去还不错了哦,我们能够监测到数据的变化,拿到了新旧数据。但是这样就完了吗?
遗憾的是我们还不能监测到数组的变化。比如:
|
|
有什么思路可以解决这个问题? 重写原型方法可以吗?像是这样:
|
|
暂且不说能不能全部实现的与原生无异,即使你实现的与原生方法在使用方式上一模一样,并且不影响其他代码的运行,那么在性能上,可能就与原生差很多了,重新考虑,我们可不可以在原型链中加一层fakePrototype,在使用 push 等数组方法的时候,调用的是 fakePrototype 上的push方法,然后在 fakePrototype 方法中再去调用真正的Array原型上的 push 方法,同时监听变化。
|
|
5.模板映射
现在,我们可以几乎完美的监测到数据对象的变化了,并且能够知道变化前后的旧值与新值,那么这样就结束了吗?当然不是,我们现在并不知道修改的是哪个属性,但是能够知道修改的是哪个属性是非常重要的。比如,我们有如下的模板:
|
|
然后有如下的数据:
|
|
我们想通过这种方式反应模板与数据之间的关系:
|
|
那么当我们的数据模型data中的某个属性改变的时候,比如 data.name = ‘kage’,如若我们不知道改变的字段名称,那么我们就无法得知要刷新哪部分模板。
那么这里就有一个路径的概念,所谓路径,就是变化的字段的路径,比如有如下数据模型:
|
|
那么字段 a 的路径就是用 data.a ,b 的路径就是 data.a.b,c 的路径就是 data.a.b.c,这里我们用数组来表述路径可以是这样:
|
|
有了这个概念之后,我们来修改之前的代码。
|
|