1.defineProperty
defineProperty其实并不是核心的为一个对象做数据双向绑定,而是去给对象做属性标签,只不过属性里的get和set实现了响应式
属性:
- value 默认值:undefined 该属性对应的值
- get 默认值:undefined 取值的时候调用的函数
- set 默认值:undefined 赋值的时候调用的函数
- writable 默认值:false 是否可写,更改
- enumerable 默认值:true 是否可枚举,可遍历
- configurable 默认值:true 是否可配置(delete权限问题)
流程:

2.简单版实现
vue2.js:
function vue (){
this.$data = {a:1}
this.el = document.getElementById('app')
this.virtualdom=""
this.observer(this.$data)
this.render()
}// 注册get 和 set
vue.prototype.observer = function (obj) {
var value
var self = this
for (var key in obj) {
value = obj[key]
if (typeof value === 'object') {
this.observer(value)
} else {
Object.defineProperty(this.$data,key,{
get:function(){
// 依赖收集
return value
},
set:function (newvalue){
value = newvalue
self.render()
}
})
}
}
}
vue.prototype.render = function () {
this.virtualdom = 'i am ' + this.$data.a
this.el.innerHTML = this.virtualdom
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app"></div>
</body>
<script src="vue2.js"></script>
<script>
var vm = new vue()
setTimeout(()=>{
console.log('changes')
console.log(vm.$data)
vm.$data.a=123
},2000)
</script>
</html>运行index.html,两秒后随着数据的改变,页面对应的dom也会发生改变
3.思考:defineProperty get 和 set 都是对象的属性,那么数组怎么办?
装饰者模式:
var arrayPro = Array.prototype
var arrOb = Object.create(arrayPro)
var arr = ['push','pop','shift']
arr.forEach(function (method,index) {
arrOb[method] = function () {
arrayPro[method].apply(this,arguments)
departFocus.notify
}
})将数组原型链上的一些方法进行重写
4.defineProperty 还可以做什么?
真正的私有变量
举例:vue-router中的$router对象不可被修改
Object.defineProperty(this,'$router',{
get (){
return this._root.router
}
})只设置get,不设置set,所以this.$router对象是不可被修改的!