-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
我们都知道Vue的核心是视图组件化和 数据驱动,本篇主要是对Vue的双向绑定原理的进行学习。
实现数据绑定的做法有大致如下几种:
-
发布者-订阅者模式(backbone.js)
-
脏值检查(angular.js)
-
数据劫持(vue.js)
数据劫持: vue.js 采用数据劫持的方式,结合发布者-订阅者模式,通过 Object.defineProperty() 来劫持各个属性的setter,getter以监听属性的变动,在数据变动时发布消息给订阅者,触发相应的监听回调。
首先我们先来看看Object.defineProperty()怎么用:
语法:
Object.defineProperty(obj, prop, descriptor)
参数说明:
obj:必需。目标对象
prop:必需。需定义或修改的属性的名字
descriptor:必需。目标属性所拥有的特性
返回值:
传入函数的对象。即第一个参数obj
例子:
var a= {}
Object.defineProperty(a,"b",{
value:123
})
console.log(a.b);//123
前两个参数不多说了,一看代码就懂,主要看第三个参数descriptor,看看有哪些取值
descriptor
- value : 属性的值(不用多说了)
- writable : 如果为false,属性的值就不能被重写,只能为只读了
- enumerable : 是否能在for...in循环中遍历出来或在Object.keys中列举出来。
- configurable : 总开关,一旦为false,就不能再设置他的(value,writable,configurable)
- get : 一会细说
- set 一会细说
注意了,当我们只设置了value的值的时候,其他特性的值都默认为false,上面的代码例子可以理解为:
var a= {}
Object.defineProperty(a,"b",{
value:123,
writable:false,
enumerable:false,
configurable:false
})
console.log(a.b);//123
我们先具体来看看writable ,enumerable ,configurable
writable:
如果设置为fasle,就变成只读了。。
var a = {};
Object.defineProperty(a,"b", {
value : 123,
writable : false });
console.log(a.b); // 打印 123
a.b = 25; // 没有错误抛出(在严格模式下会抛出,即使之前已经有相同的值)
console.log(a.b); // 打印 123, 赋值不起作用。
enumerable :
属性特性 enumerable 定义了对象的属性是否可以在 for...in 循环和 Object.keys() 中被枚举。
var a= {}
Object.defineProperty(a,"b",{
value:123,
enumerable:true
})
console.log(Object.keys(a));// ["b"]
for(var attr in a){
console.log(attr)// b
}
//改为false
var a= {}
Object.defineProperty(a,"b",{
value:123,
enumerable:false //注意咯这里改了
})
console.log(Object.keys(a));// []
for(var attr in a){
console.log(attr)// undefined
}
configurable:
总开关,第一次设置 false 之后,,第二次什么设置也不行了,比如说
var a= {}
Object.defineProperty(a,"b",{
configurable:false
})
Object.defineProperty(a,"b",{
configurable:true
})
//error: Uncaught TypeError: Cannot redefine property: b
这里要注意一下,上面讲的默认值,如果第一次不设置它,会帮你设置为false,所以再设置他,也会报错哦。。。
现在来看看属性descriptor剩下的两个方法set和get
注意:当使用了get或set方法,不允许使用writable和value这两个属性。get或set不是必须成对出现,任写其一就可以。
var obj = {};
var initValue = 'hello';
Object.defineProperty(obj,"newKey",{
get:function (){
//当获取值的时候触发的函数
return initValue;
},
set:function (value){
//当设置值的时候触发的函数,设置的新值通过参数value拿到
initValue = value;
}
});
//获取值
console.log( obj.newKey ); //hello
//设置值
obj.newKey = 'change value';
console.log( obj.newKey ); //change value
所以当我们设置了value的时候 我们获取值的时候 是直接获取我们自己设置的value;当我们设置get方法的时候,获取值的操作,是直接调用get里面的方法。
看完了上面的内容 我们利用数据劫持的方式,结合发布者-订阅者模式来实现一个极简的MVVM:
<body>
<input type="text" id="input_value"/>
<p id="p_value"></p>
</body>
<script>
let obj = { };
Object.defineProperty(obj, "a" ,{
set:(value) => {
document.getElementById('input_value').value = value ;
document.getElementById('p_value').innerHTML = value ;
}
})
document.addEventListener("keyup",(e) => {
obj.a = e.target.value ;
})
</script>
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
