1. 实现效果

2. 关于 Object.defineProperty(obj, prop, descriptor)
defineProperty 用于新增, 修改对象属性, 并返回新的对象
参数: obj 操作对象, prop 操作属性, descriptor 属性描述符
descriptor分为数据描述符和存取描述符, 两种形式不能混合使用
- 二者均可选的键值:
configurable:descriptor是否可修改以及property是否可删除, 默认为false
enumerable:property是否可被枚举, 比如Object.keys(), 默认为false - 数据描述符可选键值:
value: 属性值, 默认undefined
writable:value是否可修改, 默认为false - 存取描述符可选键值:
get: 提供getter方法, 默认为undefined
set: 提供setter方法, 默认为undefined
let obj = {}
Object.defineProperty(obj, 'name', {
value : 'Tom',
writable : true,
enumerable : true,
configurable : false
})
let email = 'hellozouzh@163.com'
Object.defineProperty(obj, "email", {
get(){
return email
},
set(newValue){
email = newValue
},
enumerable : true,
configurable : false
})
Object.keys(obj) // ['name', 'email']
obj.email // ''hellozouzh@163.com'
3. 关于 document.createDocumentFragment()
appendChild() 每一次对文档的插入都会引起页面重绘, 对于复杂的节点插入操作会导致性能问题
var ul = document.getElementById("ul")
for (var i = 0; i < 20; i++) {
var li = document.createElement("li")
li.innerHTML = "index: " + i
ul.appendChild(li)
}
DocumentFragment可以在内存之中先构建出一个复杂文档片段, 然后将这个片段一次性插入到当前文档中,
DocumentFragment节点相当于一个占位符, 本身不会被插入当前文档, 实际插入的是它的所有子孙节点,
值得注意的是一旦DocumentFragment节点被添加进当前文档, 它自身就变成了空节点
var ul = document.getElementById("ul")
var fragment = document.createDocumentFragment()
for (var i = 0; i < 20; i++) {
var li = document.createElement("li")
li.innerHTML = "index: " + i
fragment.appendChild(li)
}
ul.appendChild(fragment)
4. 实现步骤
4.1 数据劫持
使用Object.defineProperty()将new Mvvm(optios)传递进来的data中的所以属性挂载到实例vm的$data上,
通过属性描述符的get和set进行数据劫持, 监听属性的变动

4.2 数据代理
通过属性描述符的get和set将vm.$data全部代理到实例vm上, 即通过vm.price代理vm.$data.price

4.3 模板编译
通过DocumentFragment将文档树#app读取到内存当中完成变量表达式的替换 data.price -> {{ price }}

4.4 计算属性
计算属性的值依赖于data中的属性, 只要通过Object.defineProperty()把计算属性挂载到实例 vm 上即可

4.5 发布订阅
为 data 中的每个属性创建一个订阅中心data.price, 在模板编译时进行依赖收集,当属性值发生改变时通知所有依赖更新模板{{price}}


4.6 整体逻辑
