vue中的mvvm就是数据双向绑定,也就是数据model通过viewmodel影响视图view,视图view通过viewmodel影响数据model。那么他是具体怎么实现的呢?其实就是使用object.defineproperty进行数据劫持和发布订阅模式来实现。
格式:object.defineproperty(obj,'props',descriptor)
obj:要定义属性的对象
props:要定义属性的名称
descriptor:要定义和修改的属性描述
descriptor中常用的描述
configurable:为true时该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。
enumerable:为 true 时,该属性才会出现在对象的枚举属性中。就是可以用for循环输出属性
writable:为 true 时,该属性可以重新定义值
value:该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。
get:当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。
set:当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。
var obj={}
Object.defineProperty(obj,'name',{
configurable:true,
get(){ //当使用obj.name的时候回调用该函数方法
return ‘1’ //返回一个值
},set(val){ //当使用obj.name=“2” ,则调用该函数方法
console.log(val)
}
})
当使用set和get时,不能使用value和writable描述
描述符默认值汇总
拥有布尔值的键 configurable、enumerable 和 writable 的默认值都是 false。
属性值和函数的键 value、get 和 set 字段的默认值为 undefined。
var vm = new Sun({
el: '#app',
data: {
a: 1
}
})
function Sun(options = {}) {
this.$options = options; //将实例中所有的属性挂载到$options上
var data = this._data = options.data //将用户传过来的data赋值到实例_data上,并赋值给变量data利于循环
obseve(data) //调用方法,观察对象增加Object.defineproperty来设置值
for (let key in data) { //遍历data中对象,通过object.defineproperty将其赋值到对象this中
Object.defineProperty(this,key,{
enumerable:true,
get(){
return this._data[key]
},
set(newval){
this._data[key]=newval
}
})
}
}
function Observe(data) {
for (const key in data) { //将data中的属性赋值出来,对其进行定义object.defineProperty
var val = data[key]
Object.defineProperty(data, key, {
enumerable:true,
get() {
return val
},
set(newval) { //当输入vm._data.a=3 调用改方法设置新值
if (newval == val) {
return
}
val = newval; //把新的值赋值给val,以后取值的时候get就可以读到新的值
obseve(newval) // //进行递归,深度的数据观察,赋值为对象时,也要设置defineproperty
}
})
}
}
function obseve(data) {
if (typeof data!=='object') return
return new Observe(data)
}
【注】在对象中 . 是和 [ ] 的意思是一样的。例 sun.name 等价于 sun[name] , 但是for...in遍历下标中不能混淆, sun[key] 可不等价与 sun.key 。在 sun[key] 中 key等于 每一次遍历的 name,age,sex等。 而sun.key 就相当于访问sun对象的key属性