Skip to content

Commit da90898

Browse files
authored
feat: add isEqual (#396)
* feat: add isEqual * add test cace * add should throw error * add * add case * add case * add case * add case * case * improve * circular references now return false * add warning * console.error test case * fix case * case * fix case * fix case * del comment
1 parent eadf1dc commit da90898

File tree

2 files changed

+123
-0
lines changed

2 files changed

+123
-0
lines changed

src/isEqual.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import warning from './warning';
2+
3+
/**
4+
* Deeply compares two object literals.
5+
*/
6+
function isEqual(obj1: any, obj2: any): boolean {
7+
// https://github.com/mapbox/mapbox-gl-js/pull/5979/files#diff-fde7145050c47cc3a306856efd5f9c3016e86e859de9afbd02c879be5067e58f
8+
const refSet = new Set<any>();
9+
function deepEqual(a: any, b: any): boolean {
10+
const circular = refSet.has(a);
11+
warning(!circular, 'Warning: There may be circular references');
12+
if (circular) {
13+
return false;
14+
}
15+
if (a === b) {
16+
return true;
17+
}
18+
refSet.add(a);
19+
if (Array.isArray(a)) {
20+
if (!Array.isArray(b) || a.length !== b.length) {
21+
return false;
22+
}
23+
for (let i = 0; i < a.length; i++) {
24+
if (!deepEqual(a[i], b[i])) {
25+
return false;
26+
}
27+
}
28+
return true;
29+
}
30+
if (a && b && typeof a === 'object' && typeof b === 'object') {
31+
const keys = Object.keys(a);
32+
if (keys.length !== Object.keys(b).length) {
33+
return false;
34+
}
35+
return keys.every(key => deepEqual(a[key], b[key]));
36+
}
37+
// other
38+
return false;
39+
}
40+
41+
return deepEqual(obj1, obj2);
42+
}
43+
44+
export default isEqual;

src/test/isEqual.test.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import isEqual from '../isEqual';
2+
import warning from '../warning';
3+
4+
describe('isEqual', () => {
5+
let errorSpy: jest.SpyInstance;
6+
7+
beforeAll(() => {
8+
errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
9+
});
10+
11+
afterEach(() => {
12+
errorSpy.mockReset();
13+
});
14+
15+
afterAll(() => {
16+
errorSpy.mockRestore();
17+
});
18+
19+
it('should equal', () => {
20+
const valueIsEqual = isEqual(
21+
{ a: 1, b: 2, c: [1, 2] },
22+
{ a: 1, b: 2, c: [1, 2] },
23+
);
24+
expect(valueIsEqual).toBe(true);
25+
});
26+
27+
const obj = { a: 1, b: 2, c: [1, 2], obj: null };
28+
it('should equal 2', () => {
29+
const valueIsEqual = isEqual(obj, obj);
30+
expect(valueIsEqual).toBe(true);
31+
});
32+
33+
it('should not equal', () => {
34+
const valueIsEqual = isEqual(
35+
{ a: 1, b: 2, c: [2, 3] },
36+
{ a: 1, b: 'x', c: [1, 2] },
37+
);
38+
expect(valueIsEqual).toBe(false);
39+
});
40+
41+
it('should not equal 2', () => {
42+
const valueIsEqual = isEqual(
43+
{ a: 1, c: [2, 3], b: 2 },
44+
{ a: 1, c: [1, 2], b: 'x' },
45+
);
46+
expect(valueIsEqual).toBe(false);
47+
});
48+
49+
it('should not equal 3', () => {
50+
const valueIsEqual = isEqual(
51+
{ a: 1, c: [1, 2], b: 2 },
52+
{ a: 1, c: [1], b: 'x' },
53+
);
54+
expect(valueIsEqual).toBe(false);
55+
});
56+
57+
it('should not equal 4', () => {
58+
const valueIsEqual = isEqual({ a: 1, b: { c: 2 } }, { a: 1, b: 1 });
59+
expect(valueIsEqual).toBe(false);
60+
});
61+
62+
it('should not equal 5', () => {
63+
const valueIsEqual = isEqual(
64+
{ a: 1, b: { c: 2 } },
65+
{ a: 1, b: { c: 2 }, c: 1 },
66+
);
67+
expect(valueIsEqual).toBe(false);
68+
});
69+
70+
it('should not equal 6', () => {
71+
obj.obj = obj;
72+
const obj2 = { a: 1, b: 2, c: [1, 2], obj: null };
73+
warning(false, 'error');
74+
expect(errorSpy).toHaveBeenCalledWith('Warning: error');
75+
76+
const valueIsEqual = isEqual(obj, obj2);
77+
expect(valueIsEqual).toBe(false);
78+
});
79+
});

0 commit comments

Comments
 (0)