下面是demo ,有助于更好的理解
<!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>Object.defineProperty实现双向绑定</title>
</head>
<body>
<h1 id=‘h1‘></h1>
<input type="text" id="inp" onkeyup="inputChange(event)">
<input type="button" value="加" onclick="btnAdd()" />
</body>
<script>
//数据源
let vm = {
value: 0
}
//用于管理watcher的Dep对象
let Dep = function () {
this.list = [];
this.add = watcher => this.list.push(watcher),
this.notify = newValue => {
this.list.forEach(fn => {
fn(newValue)
})
}
};
// 模拟compile,通过对Html的解析生成一系列订阅者(watcher)
function renderInput(newValue) {
let el = document.getElementById(‘inp‘);
if (el) {
el.value = newValue
}
}
function renderTitle(newValue) {
let el = document.getElementById(‘h1‘);
if (el) {
el.innerHTML = newValue
}
}
//将解析出来的watcher存入Dep中待用
let dep = new Dep();
dep.add(renderInput);
dep.add(renderTitle)
console.log(dep);
console.log(Dep);
//核心方法
function initMVVM(vm) {
console.log(Object.keys(vm));
Object.keys(vm).forEach(key => {
observer(vm, key, vm[key])
})
}
function observer(vm, key, value) {
Object.defineProperty(vm, key, {
enumerable: true,
configurable: true,
get: function () {
console.log(‘Get‘);
return value
},
set: function (newValue) {
if (value !== newValue) {
value = newValue
console.log(‘Update‘)
//将变动通知给相关的订阅者
dep.notify(newValue)
}
}
})
}
//页面引用的方法
function inputChange(ev) {
let value = Number.parseInt(ev.target.value);
vm.value = (Number.isNaN(value)) ? 0 : value;
}
function btnAdd() { // 点击添加1
vm.value = vm.value + 1;
}
//初始化数据源
initMVVM(vm)
//初始化页面
dep.notify(vm.value);
</script>
</html>
1,get和set是方法,因为是方法,所以可以进行判断
2,get是得到,一般是要返回的;set是设置,不用返回
3,如果调用对象内部的属性,约定的命名方式是_age