[英]Making objects observable
最近,我一直在研究Angular和Meteor等JavaScript框架,我想知道他们如何知道何时更改了对象属性,以便可以更新DOM。
Angular使用普通的旧JS对象而不是要求您调用某种getter / setter,以便它可以挂接并进行必要的更新,这让我感到有些惊讶。 我的理解是,它们只是定期轮询对象以进行更改。
但是随着JS 1.8.5中getter和setter方法的出现,我们可以做得更好,不是吗?
作为一点概念验证,我整理了以下脚本:
( 编辑:更新代码以添加从属属性/方法支持)
function dependentProperty(callback, deps) {
callback.__dependencies__ = deps;
return callback;
}
var person = {
firstName: 'Ryan',
lastName: 'Gosling',
fullName: dependentProperty(function() {
return person.firstName + ' ' + person.lastName;
}, ['firstName','lastName'])
};
function observable(obj) {
if (!obj.__properties__) Object.defineProperty(obj, '__properties__', {
__proto__: null,
configurable: false,
enumerable: false,
value: {},
writable: false
});
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
if(!obj.__properties__[prop]) obj.__properties__[prop] = {
value: null,
dependents: {},
listeners: []
};
if(obj[prop].__dependencies__) {
for(var i=0; i<obj[prop].__dependencies__.length; ++i) {
obj.__properties__[obj[prop].__dependencies__[i]].dependents[prop] = true;
}
delete obj[prop].__dependencies__;
}
obj.__properties__[prop].value = obj[prop];
delete obj[prop];
(function (prop) {
Object.defineProperty(obj, prop, {
get: function () {
return obj.__properties__[prop].value;
},
set: function (newValue) {
var oldValue = obj.__properties__[prop].value;
if(oldValue !== newValue) {
var oldDepValues = {};
for(var dep in obj.__properties__[prop].dependents) {
if(obj.__properties__[prop].dependents.hasOwnProperty(dep)) {
oldDepValues[dep] = obj.__properties__[dep].value();
}
}
obj.__properties__[prop].value = newValue;
for(var i=0; i<obj.__properties__[prop].listeners.length; ++i) {
obj.__properties__[prop].listeners[i](oldValue, newValue);
}
for(dep in obj.__properties__[prop].dependents) {
if(obj.__properties__[prop].dependents.hasOwnProperty(dep)) {
var newDepValue = obj.__properties__[dep].value();
for(i=0; i<obj.__properties__[dep].listeners.length; ++i) {
obj.__properties__[dep].listeners[i](oldDepValues[dep], newDepValue);
}
}
}
}
}
});
})(prop);
}
}
return obj;
}
function listen(obj, prop, callback) {
if(!obj.__properties__) throw 'object is not observable';
obj.__properties__[prop].listeners.push(callback);
}
observable(person);
listen(person, 'fullName', function(oldValue, newValue) {
console.log('Name changed from "'+oldValue+'" to "'+newValue+'"');
});
person.lastName = 'Reynolds';
哪个日志:
名称从“ Ryan Gosling”更改为“ Ryan Reynolds”
我看到的唯一问题是要在person对象上定义诸如fullName()
方法,这将取决于其他两个属性。 这需要在对象上添加一些额外的标记,以允许开发人员指定依赖项。
除此之外,这种方法还有什么缺点吗?
JS 1.8.5中的getter和setter方法的问世-这种方法有什么缺点吗?
O(1)
)操作,而使用getter / setter方法可能会发生更多的事情。 您需要注意不要忘记这一点,使用实际方法可能会有所帮助。 因此,如果我们知道自己在做什么,是的,我们可以做得更好。
尽管如此,我们仍然需要记住一个重要的观点:同步/异步(也可以看看这个出色的答案 )。 Angular的脏检查允许您在下一个事件循环回合触发事件之前立即更改一堆属性。 这有助于避免语义无效状态(的传播)。
然而,我也认为同步吸气剂/吸气剂也是一个机会。 它们确实允许我们声明属性之间的依赖关系,并由此定义有效状态。 它将自动确保模型的正确性,而我们一次只需要更改一个属性(而不是始终更改firstName
和fullName
, firstName
就足够了)。 但是,在依赖关系解析过程中,这可能并不成立,因此我们需要对此加以注意。
因此,与依赖项管理无关的侦听器应异步触发。 只需setImmediate
他们的循环。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.