数据绑定
Vue.js采用Object.defineProperty
的getter
和setter
,并结合观察者模式来实现数据绑定。当把一个普通的JS对象传递给Vue实例的data
选项时,Vue将遍历它的属性,并使用Object.defineProperty
将其转化为getter
和setter
。用户看不到getter
和setter
,而在内部它们让Vue追踪依赖,在属性被访问和修改时通知变化。
- 数据监听器
Observer
数据监听器能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者。数据监听器内部采用Object.defineProperty
的getter
和setter
来实现。 - 指令解析器
Compile
指令解析器的作用是对每个元素节点进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数。 - 订阅者
Watcher
订阅者作为连接Observer
和Compile
的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数。 - 消息订阅器
Dep
消息订阅器内部维护了一个数组,用来收集订阅者,数据变动时触发notify
函数,再调用订阅者的update
方法。
Object.defineProperty
Object.defineProperty(object, property, descriptor)
Object.defineProperty
可以在对象中定义或修改某个属性并返回此对象,并能对该属性的读写进行设置。
参数 | 描述 |
---|---|
object | 需定义或修改属性的对象 |
property | 需定义或修改的属性 |
descriptor | 属性的描述符,包含存取描述符和数据描述符,以对象方式传入。 |
属性描述符 | 类型 | 描述 |
---|---|---|
value | - | 设置属性的值 |
writable | 布尔值 | 设置属性是否可写入,即是否改变value。 |
enumerable | 布尔值 | 设置属性是否可被遍历得到。 |
configurable | 布尔值 | 设置属性是否可被删除,以及除了writable外其它描述符是否可被修改。 |
get | 函数 | 属性值被获取时执行的回调函数,默认为undefined。 |
set | 函数 | 属性值被设置是执行的回调函数,默认为undefined。 |
let obj = {};
//设置属性描述符
let descriptor = {};
descriptor.value = null;//设置属性值
descriptor.enumerable = false;//设置属性禁止被遍历获得
descriptor.writable = false;//设置属性禁止被重新写入
descriptor.configurable = false;//设置属性禁止被删除
Object.defineProperty(obj, "prop", descriptor);
//使用getter和setter
let obj = {
//设置默认值
_data:{prop:0}
};
Object.defineProperty(obj,'prop',{
get(){
return obj._data.prop;
},
set(value){
obj._data.prop = value;
}
});
使用Object.defineProperty()
实现MVVM的表单中的双向数据绑定
//视图元素,获取form中的DOM节点并设置默认值,该默认值是VUE是data对象中的数据。
let form = document.querySelector(".form");
//定义对象
let object = {
_data:{
username:"",
usertype:""
}
};
//实现用户输入数据与object对象内同名属性的同步修改
Object.defineProperty(object, "username", {
get(){return object._data.username;},
set(value){object._data.username = value;}
});
Object.defineProperty(object, "usertype",{
get(){return object._data.usertype;},
set(value){object._data.usertype = value;}
});
//监听form元素事件,获取目标DOM节点的value并赋值给object对象中的响应属性,即可完成用户输入与对象值之间的数据绑定。
form.addEventListener("input", (event)=>{
let value = event.target.value;
let name = event.target.getAttribute("name");
object[name] = value;
});