In this Jasmine test我比较了几乎相同的两个对象,唯一的区别是第二个对象有一个额外的未定义成员。
describe('Testing', function () {
it('should compare two objects', function () {
var obj1 = {a: 1, b: 2 };
var obj2 = {a: 1, b: 2, c: undefined };
console.log(JSON.stringify(obj1));
console.log(JSON.stringify(obj2));
expect(obj1).toEqual(obj2);
});
测试失败,但是使用JSON.stringify
打印两个对象会产生两个相同的输出。
{"a":1,"b":2}
{"a":1,"b":2}
浏览对象可以找到差异,但在复杂对象中,这并不容易。关于如何处理这个的任何建议?
答案 0 :(得分:1)
您的问题基于两个误解:
obj2
c
中是已定义的属性,其值为undefined
。stringify()
未根据规范序列化undefined
- 您的测试不安全两个对象都是不等。
toEqual()
toEqual使用内部util.equals()
,它将按键对比 a 和 b中定义的所有可枚举键的对象键
经过某些类型检查后,它会进入comparing the keys of the object
看看ECMAscript规范。创建对象文字时会调用此内部Put
方法:
[...]
生产PropertyNameAndValueList:PropertyAssignment的计算方法如下:
- 让obj成为创建新对象的结果,就好像通过表达式new Object()一样,其中Object是具有该名称的标准内置构造函数。
- 让propId成为评估PropertyAssignment的结果。
- 使用参数propId.name,propId.descriptor和 false 调用obj的[[DefineOwnProperty]]内部方法。
- 返回obj。
醇>[...]
生产PropertyAssignment:PropertyName:AssignmentExpression的计算方法如下:
- 让propName成为评估PropertyName的结果。
- 让exprValue成为评估AssignmentExpression的结果。
- 让propValue为GetValue(exprValue)。
- 设desc为属性描述符{[[Value]]:propValue,[[Writable]]:true,[[Enumerable]]:true,[[Configurable]]:true}
醇>
通过成员表达式定义属性:
8.12.5 [[Put]](P,V,投掷) 当使用属性P,值V和布尔标志Throw调用O的[[Put]]内部方法时,将执行以下步骤:
[...]
- 醇>
否则,在对象O上创建一个名为P的命名数据属性,如下所示
一个。设newDesc为属性描述符{[[Value]]:V,[[Writable]]:true,[[Enumerable]]:true,[[Configurable]]:true}。
湾调用O的[[DefineOwnProperty]]内部方法,将P,newDesc和Throw作为参数传递。
8.12.9 [[DefineOwnProperty]] (P, Desc, Throw)中描述的DefineOwnProperty
的实施将不再重复。另外MDN says甚至默认值为undefined
。
检查:
> var obj2 = {a: 1, b: 2, c: undefined };
> obj2.hasOwnProperty("c");
< true
stringify()
查看ECMAscript spec on stringify()
或JSON spec:
(来源:json.org)
以下是ECMAscript规范的一部分:
- 否则 一个。设K是一个内部字符串列表,由[[Enumerable]]属性为true的所有值属性的名称组成。字符串的顺序应与Object.keys标准内置函数使用的顺序相同。
醇>
他们说,该对象的枚举属性应该符合Object.keys()
的顺序(和结果)。让我们测试......
> var obj2 = {a: 1, b: 2, c: undefined };
> Object.keys(obj2);
< ["a", "b", "c"]
呃,他们是对的!
然后有一个Str()
函数,它定义了处理undefined
值的行为。有几个If Type() ...
步骤,不适用于未定义的值,以
- 返回未定义。
醇>
由对象序列化程序调用时:
- 醇>
对于K的每个元素P.
一个。设strP是使用参数P和值调用抽象操作Str的结果。
湾如果strP未定义
[...]
答案 1 :(得分:0)
正如评论和其中一个答案中所解释的,两个对象都是不相等的。
幸运的是,在Jasmine 2.5中,您可以使用Custom equality tester(定义自己的等号)解决此问题:
ID = -335362046
Closing handle 3959605250
There is not an open file with that identification number.
More help is available by typing NET HELPMSG 2314.
将此插入function customEquality(a, b) {
let keys,
key,
equal = true;
// Store unique list of keys over both objects
keys = Object.keys(a).concat(Object.keys(b)).reduce(function(result, name) {
if (!result.includes(name)) {
result.push(name);
}
return result;
}, []);
for (key of keys) {
// ignore when keys are defined in both objects,
// having the value undefined
if (typeof a[key] === "undefined" && a.hasOwnProperty(key) &&
typeof b[key] === "undefined" && b.hasOwnProperty(key)) {
continue;
}
equal = equal && b[key] === a[key];
}
return equal;
}
jasmine.addCustomEqualityTester(customEquality);
与测试相同的块中或实际beforeEach()
内。
此基本测试程序将忽略两个对象中存在的未定义值。如果一个对象中存在未定义的值,则不会将其视为相等。
请注意,此测试程序与纯it()
的行为有很大不同,因为它不会比较Arrays或嵌套对象,也不会比较DOM节点等其他对象类型。这只是一个指导你的例子。