我正在编写一个Javascript程序,部分程序状态是一个对象。我想定期计算状态并将其与当前状态进行比较以确定是否应该触发事件,这里是一些伪代码:
var newState = calculateState();
if (newState !== oldState) {
triggerEvent();
}
但是,由于状态是一个对象,我需要进行值相等检查以及防止空引用检查。也就是说,如果状态从非空值变为空或反之,我还需要触发事件:
if (newState === null && oldState !== null || // non null -> null
newState !== null && oldState === null || // null -> non null
(newState !== null && oldState !== null && // both non null, check members
(newState.age !== oldState.age ||
newState.name !== oldState.name))) {
triggerEvent();
}
正如您所看到的,代码非常混乱和丑陋。
有没有办法在Javascript中重构这个?
谢谢!
答案 0 :(得分:2)
如果为了更干净的代码,我建议在单独的函数中处理两个对象之间的比较,如下所示:
ar newState = calculateState();
// areEqual() takes the two objects as parameters
if (areEqual(oldState, newState)) {
triggerEvent();
}
然后确定该函数中两个对象是否相等
// This function compares two state objects and returns true if they are valid and different
function areEqual(oldState, newState){
return (newState === null && oldState !== null || // non null -> null
newState !== null && oldState === null || // null -> non null
(newState !== null && oldState !== null && // both non null, check members
(newState.age !== oldState.age || newState.name !== oldState.name)));
}
答案 1 :(得分:1)
if (n === null && o !== null || // non null -> null
n !== null && o === null || // null -> non null
(n !== null && o !== null && // both non null, check members
(n.age !== o.age ||
n.name !== o.name))) {
triggerEvent();
}
让我们打破这一点(我使用n
和o
缩写来更多地放在一行上,以便更容易看到发生了什么 - 不建议使用这个简洁的约定):
n === null && o !== null ||
n !== null && o === null
此表达式可简化为:n !== o
。
这是有效的,因为如果一个为null而不是另一个,则表达式将评估true。如果对象指向相同的内存地址,这也将返回false(这是一件好事,因为它们的字段也匹配,我们不希望在这种情况下触发事件)。
这样我们就到了这里:
if (n !== o ||
((n !== null && o !== null) &&
(n.age !== o.age || n.name !== o.name))) {
triggerEvent();
}
为了简化,通常需要引入功能。如果你为这些状态提供一个比较这些age
和name
字段的相等方法,那么你可能会做很多事情。如果您添加新状态,它还会使代码更不容易出错。
空交换技巧
有时以几个周期为代价的另一个技巧是对之间的空交换。例如:
// if 'a' is null:
if (!a)
{
// swap it with 'b'.
a = [b, b = a][0];
}
// Now if 'a' is still null, both values are null.
// If 'b' is not null, both values are not null.
我们可以在上面的代码中使用它,如下所示:
local state1 = oldState
local state2 = newState
if (!state1)
state1 = [state2, state2 = state1][0];
if (state1) {
// If only one of these is not null or their fields don't match:
if (!state2 || state1.age !== state2.age || state1.name !== state2.name) {
triggerEvent();
}
}
这种简化或复杂化的大部分将取决于您使用这种简洁交换单行的频率。如果它非常罕见,那可能只会增加混乱。但是这种交换技术可以让你编写稍微冗长的代码,以换取代码,这些代码可能更直接,并且不会压倒你的大脑堆栈(有时更简单的代码比需要嵌套非常人工解析的一些非常复杂的东西更好)。