VUE双向数据绑定核心功能由Observer、Compile、Watcher三部分实现,其中Observer部分功能实现由Object.defineProperty实现。
1)Observer:监测数据变化进行相应回调(数据劫持);
实现一个简单的数据劫持,作为Object.defineProperty的练习。从而引出Proxy&Reflect
<!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>
<input type="text" id='demo'/>
<div id='show'></div>
<script>
var oDiv = document.getElementById('show');
var oInput = document.getElementById('demo');
var oData = {
//valueObj: {
// value: '你陈哥',
// name: 'haha'
//},
value: '你陈哥',
sex: 'aaa'
};
oInput.oninput = function () {
oData.value = this.value;
//oData.valueObj.value = this.value;
};
function upDate () {
oDiv.innerText = oData.value;
//oDiv.innerText = oData.valueObj.value;
}
// 监控对象的某个属性是否发生改变
function Observer (data) {
if (!data || typeof data != 'object') {
return data;
};
// for (var prop in data) {
// }
Object.keys(data).forEach(function (key) {
definedRective(data, key, data[key]);
});
}
function definedRective (data, key, val) {
// AO
//Observer(val);
Object.defineProperty(data, key, {
get () {
// console.log('get');
return val;
},
set (newValue) {
if (newValue == val) return;
val = newValue;
upDate();
}
})
};
Observer(oData);
我们一开始在定义一个oData对象,对象里面有个属性value,并设置了属性值。
接着绑定oninput事件,监听input框中值的改变将input框中的值赋给obj.value,并通过upData函数将input框中的值插入oDiv中。
构造Observer函数监控对象的某个属性是否发生改变(1.判断数据是否传进去、数据是不是对象2.VUE中Object.defineProperty一般不存在于Observer函数中,而是重新定义一个函数definedRective3.definedRective函数在判断数据是否改变,通过if操作判断重新输入个数据是否与输入前的数据相同,以优化性能)
完成这些操作对于VUE而言还不够,如何将数组中的数据展现在视图呢?
2)vue3.0以前的版本在数组上的操作,其实也很简单,就是把数组上的方法给重写了
let arr = [];
let {push} = Array.prototype;
function upData () {
console.log('更新');
};
// [
// 'push',
// 'pop'
// ]
// arr push pop unshift shift slice....
Object.defineProperty(Array.prototype, 'push', {
value: (function () {
return (...arg) => {
push.apply(arr, arg);
upData();
}
})()
});
arr.push(1, 2);
当然VUE通过Observer监控数据变化是有额外的问题。当我们在前边加载Observer最后加上一句oData.aa = 10;难道Observer还要重新加载一遍吗?而在Proxy Reflect中就很好的解决了这一问题。但是,兼容性不是很好