defineProperty实现数据代理
- vue2 响应式原理
Vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty()来劫持各个属性的 setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。主要分为以下几个步骤:
- 需要 observe 的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter 和 getter 这样的话,给这个对象的某个值赋值,就会触发 setter,那么就能监听到了数据变化
- compile 解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
- Watcher 订阅者是 Observer 和 Compile 之间通信的桥梁,主要做的事情是: ① 在自身实例化时往属性订阅器(dep)里面添加自己 ② 自身必须有一个 update()方法 ③ 待属性变动 dep.notice()通知时,能调用自身的 update()方法,并触发 Compile 中绑定的回调,则功成身退。
- MVVM 作为数据绑定的入口,整合 Observer、Compile 和 Watcher 三者,通过 Observer 来监听自己的 model 数据变化,通过 Compile 来解析编译模板指令,最终利用 Watcher 搭起 Observer 和 Compile 之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据 model 变更的双向绑定效果。
define定义;property属性;所以这个defineproperty方法是用来添加属性用的(或者说给一个对象定义属性用的)既然是为对象中添加属性用的,那我得现有一个对象
首先要传三个参数:
- 第一个:你要给哪个对象添加参数
- 第二个:您添加的属性叫什么名
- 第三个:重要的参数(配置项),最常用的就是
value - 配置项中还有几个可控制配置项
- enumerable: true //控制属性是否可以枚举,默认是false
- writable: true, //控制属性是否可以被修改,默认值是false
- configurable: true //控制属性是否可以被删除,默认值是false
这样写完,你的
person就多出了一个age属性并且值是18
这种方法看起来麻烦,但是它比较高级用Object.defineProperty()出来的属性是不能被枚举的(不参与遍历的)
要先遍历借助另一个配置项(enumerable可列举的)
Object.defineProperty()里面的属性不能被删除
要想删除可以使用一个配置项configurable
number和person是俩个东西,但是借助了Object.defineProperty(),这俩个值进行了关联
age通过get()去取,通过set去修改
vm身上有的这俩个name和address属性它们都是靠defineProperty加上去的;也就是说当有人访问vm身上的name的时候getter工作,把一个别的地方的name拿过来用
如果有人通过vm修改这个name,这时setter就要工作,但这个地方是哪呢?
其实就是data()说直白点也没有别的地方配置name这么说name和address要有自己的setter和getter;确实有
我通过vm读name读的是data中的name;通过vm来改name也是data中的name
总结
1、Vue中的数据代理:通过vm对象来代理data对象中属性的操作(读/写)
2、Vue中数据代理好处: 更加方便操作data中的数据
3、基本原理: 通过Object.defineProperty()把data对象中所有的属性添加到vm上。为每一个添加到vm上的属性,都指定一个getter/setter。在getter/setter内部去操作(读/写)data中对应的属性。