gpt4 book ai didi

javascript - 使对象可观察

转载 作者:数据小太阳 更新时间:2023-10-29 04:20:46 24 4
gpt4 key购买 nike

我最近一直在研究 Angular 和 Meteor 等 JavaScript 框架,我想知道它们如何知道对象属性何时发生更改,以便它们可以更新 DOM。

我有点惊讶 Angular 使用普通的旧 JS 对象而不是要求您调用某种 getter/setter 以便它可以挂接并进行必要的更新。我的理解是他们只是定期轮询对象以获取更改。

但随着 getter 和 setter 在 JS 1.8.5 中的出现,我们可以做得更好,不是吗?

作为一点概念验证,我将这个脚本放在一起:

(编辑:更新代码以添加依赖属性/方法支持)

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';

哪些日志:

Name changed from "Ryan Gosling" to "Ryan Reynolds"

我看到的唯一问题是在 person 对象上定义诸如 fullName() 之类的方法,这将取决于其他两个属性。这需要在对象上做一些额外的标记,以允许开发人员指定依赖关系。

除此之外,这种方法还有什么缺点吗?

JsFiddle

最佳答案

advent of getters and setters in JS 1.8.5 - are there any downsides to this approach?

  • 除了观察到的变化之外,您不会捕获任何属性变化。当然,这对于建模实体对象以及我们可以使用代理的任何其他对象来说已经足够了。
  • 它仅限于支持 getters/setters 甚至代理的浏览器。但是,嘿,谁会关心过时的浏览器? :-) 而在受限环境 (Node.js) 中,这根本不成立。
  • 访问属性(带有 getter 和 setter)比真正的 get/set 方法慢得多。当然我不希望它们被用在关键部分,它们可以让代码看起来更漂亮。然而,您需要将其牢记在心。此外,花哨的代码可能会导致误解 - 通常您会期望属性分配/访问是一个简短的 (O(1)) 操作,而对于 getters/setters 可能会有很多更多的发生。您需要注意不要忘记这一点,使用实际方法可能会有所帮助。

因此,如果我们知道自己在做什么,是的,我们可以做得更好。

不过,我们需要记住一个重要的点:同步/异步(另请参阅 this excellent answer)。 Angular 的脏检查允许您在下一次事件循环中之前事件触发时立即更改一堆属性。这有助于避免(传播)语义无效状态。

但我也将同步 getter/setter 视为一种机会。它们确实允许我们声明属性之间的依赖关系并由此定义有效状态。它会自动确保模型的正确性,而我们一次只需更改一个属性(而不是一直更改 firstNamefullNamefirstName 就够了)。然而,在依赖解析期间,这可能不成立,所以我们需要关心它。

因此,与依赖管理无关的监听器应该被异步触发。只是 setImmediate 他们的循环。

关于javascript - 使对象可观察,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14796148/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com