实现从数据层到view层绑定
Object.observe()是一种新特性,其在ES7中实现,但在最新的Chrome中已可用 —— 允许对JS对象进行响应式更新。简单说就是 —— 只要对象(的属性)发生变化就调用回调函数。
user = {}
Object.observe(user, function(changes){
changes.forEach(function(change) {
user.fullName = user.firstName + " " + user.lastName;
});
});
user.firstName = 'Bill';
user.lastName = 'Clinton';
user.fullName // 'Bill Clinton'
这很方便,且能实现响应式编程 —— 保证所有内容都是最新的。
如下:
//<input id="foo">
user = {};
div = $("#foo");
Object.observe(user, function(changes){
changes.forEach(function(change) {
var fullName = (user.firstName || "") + " " + (user.lastName || "");
div.text(fullName);
});
});
user.firstName = 'Bill';
user.lastName = 'Clinton';
div.text() //Bill Clinton
这也就实现从数据层到view层的数据绑定,view层到数据层的绑定可以通过绑定dom事件来实现。
深入get和set属性
user = {}
nameValue = 'Joe';
Object.defineProperty(user, 'name', {
get: function(){ return nameValue },
set: function(newValue){ nameValue = newValue; },
configurable: true//to enable redefining the property later
});
user.name //Joe
user.name = 'Bob'
user.name //Bob
nameValue //Bob
现在user.name是nameValue的别名。但可做的不仅仅是创建新的变量名 - 我们可以通过它来保证模型和视图的一致。
//<input id="foo">
Object.defineProperty(user, 'name', {
get: function() { returndocument.getElementById("foo").value },
set: function(newValue) { document.getElementById("foo").value = newValue; },
configurable: true//to enable redefining the property later
});
可封装如下:
functionbindModelInput(obj, property, domElem) {
Object.defineProperty(obj, property, {
get: function() { return domElem.value; },
set: function(newValue) { domElem.value = newValue; },
configurable: true
});
}
上面的实现中,在某些场景下,视图可认为是符合SPOT (single point of truth )原则的,但该原则常常被忽视(因为双向数据绑定也就意味着等价)。然而,深究下去可能就会发现问题了,在实际开发中也会遇到。 —— 比如,当删除DOM元素时,关联的模型会自动注销么?答案是不会。bindModelInput函数在domElem元素上创建了一个闭包,使DOM元素常驻在内存中 —— 并保持模型与模型的绑定关系 —— 即使DOM元素被移除。即使视图被移除了,但模型依旧存在。反之一样 —— 若模型被移除了,视图依然能够正常显示。在某些刷新视图和模型无效的情况下,理解这些内部原理就能找到原因了。