Javascript对象值相等测试
Javascript object value equality test?
我正在编写一个Javascript程序,程序状态的一部分是对象。我想定期计算状态,并将其与当前状态进行比较,以决定是否应该触发事件,下面是一些伪代码:
var newState = calculateState();
if (newState !== oldState) {
triggerEvent();
}
然而,由于状态是一个对象,我需要进行值相等性检查以及防止空引用检查。也就是说,如果状态从非null值变为null或相反,我还需要触发事件:
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中重构它?
谢谢!
如果是为了更干净的代码,我建议在单独的函数中处理两个对象之间的比较,如下所示:
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)));
}
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,而另一个不为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();
}
}
这是简化还是复杂,很大程度上取决于你使用这种简洁的交换一行的频率。如果这种情况非常罕见,那可能只会加剧混乱。但这种交换技术可以让你写稍微更详细的代码,以换取可能更直接、不会让你的大脑堆栈不堪重负的代码(有时更简单的代码比一些需要嵌套的、非常人性化的解析的非常复杂的东西更可取)。
- 测试对象是否相等和/或对象是否有更多的关键点,但仍然与共同的关键点相等
- 使用 Jasmine 测试对象中的事件处理程序
- 如何使用Ramda通过“where”比较测试对象中的属性值
- 测试对象数组中是否存在值
- 测试对象是否是 Google 闭包类框架中接口的实现
- 是否有函数可以测试对象是否与其他对象匹配
- 为网站自动化生成 JavaScript 测试对象的最佳方法是什么?
- 使用 Lodash 或 AngularJS 测试对象中是否存在值的最简单方法是什么?
- 如何在 JSON 字符串中选择两个测试对象并将它们映射到我的接口
- 柴断言测试对象结构是否至少包含其他对象结构
- Jasmine测试对象方法
- 测试对象数组中的值
- 测试对象上的属性是否是单个可观察的(而不是observableArray)
- 如何在IE8中测试对象文字
- 如何测试对象的可选成员
- 什么是深度测试对象的简明方法hasOwnProperty(或类似方法)
- 如何测试对象"isEmpty()"如果对象.原型被修改
- 在不同浏览器上测试对象delete值的问题
- 茉莉花测试:对象没有't支持属性或方法
- 在Ajax方法间谍调用上测试对象的茉莉花状态