什么是双向绑定
首先来说一下单向绑定,单向绑定就是把 Model 绑定到 View,当我们用 JS 代码更新 Model 时,View 就会自动更新。
有单向绑定,就有双向绑定。如果用户更新了 View,Model 的数据也自动被更新了,这种情况就是双向绑定。
object.defineProperty
Object.defineProperty 是 ES5 中双向绑定的方法,下面开始介绍它的语法
Object.defineProperty(obj, prop, descriptor);
// Object.defineProperty(对象, 属性, 描述符)
/* descriptor 对象属性的详细介绍 */
/* 描述符 */
value: "" // 属性值 默认 ''
weitable: true // 是否可写 默认值 false
configurable: true //是否可配置 默认值 false
enumerable: true // 是否可枚举 默认值 false
/* 存取描述符 */
set: function(){} // 属性访问器 进行写操作时调用该方法
get: function(){} // 属性访问器 进行读操作时调用该方法
描述符介绍
我们在正常声明一个对象,都是可写,可配置,可枚举的。例如:
let a = {
name:'ccc'
}
a.name = "xxx" // weitable可写
for(let i in a){
console.log(i) // 输出 name 说明 enumerable 可枚举
}
delete a.name // 返回 true configurable 可配置
使用 Object.defineProperty
var a = {
}
Object.defineProperty(a,"name",{
value: 'ccc',
})
a.name = "xxx"; // a.name 返回的还是 ccc
delete a.name // 返回 false
for(var i in a){
console.log(i) //返回 undefined
}
因为我通过 Object.defineProperty
设置的属性和属性值,后面的 weitable(写入)、configurable(配置)、enumerable(枚举) 都是默认值 false,所以不可写入,不可配置,不可枚举的。
var a = {
}
Object.defineProperty(a,"name",{
value: 'ccc',
weitable: true
configurable: true,
enumerable: true
})
a.name = "xxx"; // a.name 返回 xxx
delete a.name // 返回 true
for(var i in a){
console.log(i) //返回 name
}
在设置 weitable(写入)、configurable(配置)、enumerable(枚举)这三个属性为 true 之后,就可以进行写入、配置、枚举操作。
存取描述符
我们下一下面的例子
var a = {
}
Object.defineProperty(a,"name",{
// 在设置 get 和 set 之后 value weitable 这两个属性就不能设置了
// 在设置 get 和 set 之后 value weitable 不能共存
configurable: true,
enumerable: true,
get: function (){
console.log('执行get了');
},
set: function(){
console.log('执行set了');
}
})
a.name = "ccc"; // 输出 执行 set 了
console.log(a.name); // 输出 执行 get 了
在上面代码中 a.name
被赋值 ccc
,被 set 方法监听到执行 console.log('执行get了')
。之后又访问 a.name
被 set 方法监听到执行 console.log('执行set了')
。
var val;
var a = {
}
Object.defineProperty(a,"name",{
// 在设置 get 和 set 之后 value weitable 这两个属性就不能设置了
// 在设置 get 和 set 之后 value weitable 不能共存
configurable: true,
enumerable: true,
get: function (){
console.log('执行get了');
return val;
},
set: function(newVal){
console.log('执行set了');
val = newVal;
console.log(val);
}
})
a.name = "ccc"; // 输出 执行 set 了 并且执行 set 里面 console.log(val) 是 ccc;
console.log(a.name); // 输出 执行 get 了 打印 a.name 是 ccc
简单的模拟一下双向绑定
VUE2.0 双向数据绑定核心功能由 Observe、Compile、Watcher 三部分实现。其中 Observer 的部分功能由 Object.defineProperty
实现。(Observer 监测数据变化进行相应回调)。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input type="text" id='inputDemo'/>
<div id="txt"></div>
</body>
<script>
var data = {
value: 'ccc',
name:{
nameData: "ttt"
}
}
inputDemo.oninput = function(){
data.name.nameData = this.value;
}
function upData (){
txt.innerText = data.name.nameData;
}
upData();
// 监控对象的某个属性是否发生改变
function Observer (obj) {
// 判断 obj 是否存在或类型不是对象 如果是直接返回 obj
if(!obj || typeof obj != 'object') return obj;
// 通过 keys 拿到 obj 的属性,之后在循环一个一个拿出来
Object.keys(obj).forEach(function(ele){
// 执行 defineReactive(监听的对象, 监听对象的属性, 属性值)
defineReactive(obj,ele,obj[ele]);
})
}
function defineReactive (obj,ele,value) {
// 执行递归 value 里面还有没有深层的对象
Observer(value);
// 开始监听
Object.defineProperty(obj,ele,{
get(){
console.log("执行了get")
return value;
},
set(newVal){
console.log("执行了set");
if(newVal == value) return
value = newVal;
upData();
}
});
}
// 调用监听的方法
Observer(data);
data.value = 'xxx';
</script>
</html>
通过这种方式写就可以实现 input 和 div 实现一个双向绑定。
数组双向绑定
Object.defineProper
不支持数组的监听,可以用 array.prototype
原型对象
var arr = [];
var push = Array.prototype.push
function upData () {
console.log('数组更新了')
}
var arrFun = ["pop","shift","unshift","splice ","splice", 'push']
Object.defineProperty(Array.prototype, arrFun[5], {
value: (function(){
return function (){
push.apply(arr, [].slice.call(arguments));
}
})()
});
arr[arrFun[5]](1,2);
Object.defineProperty
除了支持监听数组之外,还对 Observer
之后新增的对象也不支持监听
var data = {
value: 'ccc',
name:{
nameData: "ttt"
}
}
// 监控对象的某个属性是否发生改变
function Observer (obj) {
// ...
}
function defineReactive (obj,ele,value) {
// ...
}
// 调用监听的方法
Observer(data);
data.a = 10; // Object.defineProperty 对这个属性 不支持监听
// 因为在 Observer() 之后
网友评论