参考:剖析Vue原理&实现双向绑定MVVM和Vue.js双向绑定的实现原理
1、通过Object.defineProperty(obj, prop, descriptor)劫持对象的属性读写,其中obj是要在上面定义属性的对象,prop是要定义或修改的属性名称,descriptor是属性的描述符。描述符中可选get和set键值。get是属性的getter方法,返回属性值;set为setter方法,接受唯一参数,并将该参数的值赋值给属性,get和set的默认值均为undefined。
2、双向绑定的简单实现。
<input type="input" id="input">
<span id="show"></span>
<script>
var obj = {};
Object.defineProperty(obj, 'txt', {
get: function () {
return obj;
},
set: function (newValue) {
document.getElementById('input').value = newValue;
document.getElementById('show').innerHTML = newValue;
}
});
document.getElementById('input').addEventListener('keyup', function (e) {
obj.txt = e.target.value;
});
</script>
当通过input进行输入时,obj.txt的值会相应更新;当通过控制台改变obj.txt的值时,setter会改变view,从而实现了view=>model,model=>view的双向绑定。不过这种简单绑定不会真正执行obj.txt = e.target.value,obj永远为{},如果在set方法中赋值obj.txt = e.target.value,则会造成无限循环。为解决这个问题,将Object.defineProperty()封装为一个函数,即可在其中保存状态obj.txt,修改如下:
<input type="text" id="input">
<div id="show"></div>
<script>
function defineProperty(obj, attr){
var val;
Object.defineProperty(obj, attr, {
get: function () {
return val;
},
set: function (newValue) {
if (newValue === val){
return;
}
val = newValue;
document.getElementById("input").value = newValue;
document.getElementById("show").innerHTML = newValue;
}
});
}
var obj = {};
defineProperty(obj, "txt");
document