严格相等运算符将告诉您两个对象类型是否相等。然而,是否有一种方法来判断两个对象是否相等,就像Java中的哈希码值一样?
堆栈溢出问题JavaScript中有hashCode函数吗?类似于这个问题,但需要一个更学术的答案。上面的场景说明了为什么有必要有一个,我想知道是否有等效的解决方案。
严格相等运算符将告诉您两个对象类型是否相等。然而,是否有一种方法来判断两个对象是否相等,就像Java中的哈希码值一样?
堆栈溢出问题JavaScript中有hashCode函数吗?类似于这个问题,但需要一个更学术的答案。上面的场景说明了为什么有必要有一个,我想知道是否有等效的解决方案。
当前回答
我不知道是否有人发布过类似的东西,但这是我做的一个检查对象相等的函数。
function objectsAreEqual(a, b) {
for (var prop in a) {
if (a.hasOwnProperty(prop)) {
if (b.hasOwnProperty(prop)) {
if (typeof a[prop] === 'object') {
if (!objectsAreEqual(a[prop], b[prop])) return false;
} else {
if (a[prop] !== b[prop]) return false;
}
} else {
return false;
}
}
}
return true;
}
而且,它是递归的,所以它也可以检查深度相等,如果你这么称呼它的话。
其他回答
let user1 = { name: "John", address: { line1: "55 Green Park Road", line2: { a:[1,2,3] } }, email:null } let user2 = { name: "John", address: { line1: "55 Green Park Road", line2: { a:[1,2,3] } }, email:null } // Method 1 function isEqual(a, b) { return JSON.stringify(a) === JSON.stringify(b); } // Method 2 function isEqual(a, b) { // checking type of a And b if(typeof a !== 'object' || typeof b !== 'object') { return false; } // Both are NULL if(!a && !b ) { return true; } else if(!a || !b) { return false; } let keysA = Object.keys(a); let keysB = Object.keys(b); if(keysA.length !== keysB.length) { return false; } for(let key in a) { if(!(key in b)) { return false; } if(typeof a[key] === 'object') { if(!isEqual(a[key], b[key])) { return false; } } else { if(a[key] !== b[key]) { return false; } } } return true; } console.log(isEqual(user1,user2));
这是一个通用的相等检查函数,它接收数组元素作为输入,并将它们相互比较。适用于所有类型的元素。
const isEqual = function(inputs = []) {
// Checks an element if js object.
const isObject = function(data) {
return Object.prototype.toString.call(data) === '[object Object]';
};
// Sorts given object by its keys.
const sortObjectByKey = function(obj) {
const self = this;
if (!obj) return {};
return Object.keys(obj).sort().reduce((initialVal, item) => {
initialVal[item] = !Array.isArray(obj[item]) &&
typeof obj[item] === 'object'
? self.objectByKey(obj[item])
: obj[item];
return initialVal;
}, {});
};
// Checks equality of all elements in the input against each other. Returns true | false
return (
inputs
.map(
input =>
typeof input == 'undefined'
? ''
: isObject(input)
? JSON.stringify(sortObjectByKey(input))
: JSON.stringify(input)
)
.reduce(
(prevValue, input) =>
prevValue === '' || prevValue === input ? input : false,
''
) !== false
);
};
// Tests (Made with Jest test framework.)
test('String equality check', () => {
expect(isEqual(['murat'])).toEqual(true);
expect(isEqual(['murat', 'john', 'doe'])).toEqual(false);
expect(isEqual(['murat', 'murat', 'murat'])).toEqual(true);
});
test('Float equality check', () => {
expect(isEqual([7.89, 3.45])).toEqual(false);
expect(isEqual([7, 7.50])).toEqual(false);
expect(isEqual([7.50, 7.50])).toEqual(true);
expect(isEqual([7, 7])).toEqual(true);
expect(isEqual([0.34, 0.33])).toEqual(false);
expect(isEqual([0.33, 0.33])).toEqual(true);
});
test('Array equality check', () => {
expect(isEqual([[1, 2, 3], [1, 2, 3]])).toEqual(true);
expect(isEqual([[1, 3], [1, 2, 3]])).toEqual(false);
expect(isEqual([['murat', 18], ['murat', 18]])).toEqual(true);
});
test('Object equality check', () => {
let obj1 = {
name: 'murat',
age: 18
};
let obj2 = {
name: 'murat',
age: 18
};
let obj3 = {
age: 18,
name: 'murat'
};
let obj4 = {
name: 'murat',
age: 18,
occupation: 'nothing'
};
expect(isEqual([obj1, obj2])).toEqual(true);
expect(isEqual([obj1, obj2, obj3])).toEqual(true);
expect(isEqual([obj1, obj2, obj3, obj4])).toEqual(false);
});
test('Weird equality checks', () => {
expect(isEqual(['', {}])).toEqual(false);
expect(isEqual([0, '0'])).toEqual(false);
});
这里还有一个要点
function isEqual(obj1, obj2){
type1 = typeof(obj1);
type2 = typeof(obj2);
if(type1===type2){
switch (type1){
case "object": return JSON.stringify(obj1)===JSON.stringify(obj2);
case "function": return eval(obj1).toString()===eval(obj2).toString();
default: return obj1==obj2;
}
}
return false;
}//have not tried but should work.
我已经实现了一个方法,它接受两个json,并使用递归检查它们的键是否具有相同的值。 我用另一个问题来解决这个问题。
const arraysEqual = (a, b) => { if (a === b) return true; if (a === null || b === null) return false; if (a.length !== b.length) return false; // If you don't care about the order of the elements inside // the array, you should sort both arrays here. for (let i = 0; i < a.length; ++i) { if (a[i] !== b[i]) return false; } return true; }; const jsonsEqual = (a, b) => { if(typeof a !== 'object' || typeof b !== 'object') return false; if (Object.keys(a).length === Object.keys(b).length) { // if items have the same size let response = true; for (let key in a) { if (!b[key]) // if not key response = false; if (typeof a[key] !== typeof b[key]) // if typeof doesn't equals response = false; else { if (Array.isArray(a[key])) // if array response = arraysEqual(a[key], b[key]); else if (typeof a[key] === 'object') // if another json response = jsonsEqual(a[key], b[key]); else if (a[key] !== b[key]) // not equals response = false; } if (!response) // return if one item isn't equal return false; } } else return false; return true; }; const json1 = { a: 'a', b: 'asd', c: [ '1', 2, 2.5, '3', { d: 'asd', e: [ 1.6, { f: 'asdasd', g: '123' } ] } ], h: 1, i: 1.2, }; const json2 = { a: 'nops', b: 'asd' }; const json3 = { a: 'h', b: '484', c: [ 3, 4.5, '2ss', { e: [ { f: 'asdasd', g: '123' } ] } ], h: 1, i: 1.2, }; const result = jsonsEqual(json1,json2); //const result = jsonsEqual(json1,json3); //const result = jsonsEqual(json1,json1); if(result) // is equal $('#result').text("Jsons are the same") else $('#result').text("Jsons aren't equals") <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div id="result"></div>
从我的个人库中取出,我经常用它来工作。下面的函数是一个宽大的递归深度等号,它不检查
阶级平等 继承的值 价值观严格平等
我主要用这个来检查我是否得到了对各种API实现的相等的回复。可能会出现实现差异(如字符串与数字)和额外的空值。
它的实现非常简单(如果去掉所有注释的话)
/** Recursively check if both objects are equal in value *** *** This function is designed to use multiple methods from most probable *** (and in most cases) valid, to the more regid and complex method. *** *** One of the main principles behind the various check is that while *** some of the simpler checks such as == or JSON may cause false negatives, *** they do not cause false positives. As such they can be safely run first. *** *** # !Important Note: *** as this function is designed for simplified deep equal checks it is not designed *** for the following *** *** - Class equality, (ClassA().a = 1) maybe valid to (ClassB().b = 1) *** - Inherited values, this actually ignores them *** - Values being strictly equal, "1" is equal to 1 (see the basic equality check on this) *** - Performance across all cases. This is designed for high performance on the *** most probable cases of == / JSON equality. Consider bench testing, if you have *** more 'complex' requirments *** *** @param objA : First object to compare *** @param objB : 2nd object to compare *** @param .... : Any other objects to compare *** *** @returns true if all equals, or false if invalid *** *** @license Copyright by eugene@picoded.com, 2012. *** Licensed under the MIT license: http://opensource.org/licenses/MIT **/ function simpleRecusiveDeepEqual(objA, objB) { // Multiple comparision check //-------------------------------------------- var args = Array.prototype.slice.call(arguments); if(args.length > 2) { for(var a=1; a<args.length; ++a) { if(!simpleRecusiveDeepEqual(args[a-1], args[a])) { return false; } } return true; } else if(args.length < 2) { throw "simpleRecusiveDeepEqual, requires atleast 2 arguments"; } // basic equality check, //-------------------------------------------- // if this succed the 2 basic values is equal, // such as numbers and string. // // or its actually the same object pointer. Bam // // Note that if string and number strictly equal is required // change the equality from ==, to === // if(objA == objB) { return true; } // If a value is a bsic type, and failed above. This fails var basicTypes = ["boolean", "number", "string"]; if( basicTypes.indexOf(typeof objA) >= 0 || basicTypes.indexOf(typeof objB) >= 0 ) { return false; } // JSON equality check, //-------------------------------------------- // this can fail, if the JSON stringify the objects in the wrong order // for example the following may fail, due to different string order: // // JSON.stringify( {a:1, b:2} ) == JSON.stringify( {b:2, a:1} ) // if(JSON.stringify(objA) == JSON.stringify(objB)) { return true; } // Array equality check //-------------------------------------------- // This is performed prior to iteration check, // Without this check the following would have been considered valid // // simpleRecusiveDeepEqual( { 0:1963 }, [1963] ); // // Note that u may remove this segment if this is what is intended // if( Array.isArray(objA) ) { //objA is array, objB is not an array if( !Array.isArray(objB) ) { return false; } } else if( Array.isArray(objB) ) { //objA is not array, objB is an array return false; } // Nested values iteration //-------------------------------------------- // Scan and iterate all the nested values, and check for non equal values recusively // // Note that this does not check against null equality, remove the various "!= null" // if this is required var i; //reuse var to iterate // Check objA values against objB for (i in objA) { //Protect against inherited properties if(objA.hasOwnProperty(i)) { if(objB.hasOwnProperty(i)) { // Check if deep equal is valid if(!simpleRecusiveDeepEqual( objA[i], objB[i] )) { return false; } } else if(objA[i] != null) { //ignore null values in objA, that objB does not have //else fails return false; } } } // Check if objB has additional values, that objA do not, fail if so for (i in objB) { if(objB.hasOwnProperty(i)) { if(objB[i] != null && !objA.hasOwnProperty(i)) { //ignore null values in objB, that objA does not have //else fails return false; } } } // End of all checks //-------------------------------------------- // By reaching here, all iteration scans have been done. // and should have returned false if it failed return true; } // Sanity checking of simpleRecusiveDeepEqual (function() { if( // Basic checks !simpleRecusiveDeepEqual({}, {}) || !simpleRecusiveDeepEqual([], []) || !simpleRecusiveDeepEqual(['a'], ['a']) || // Not strict checks !simpleRecusiveDeepEqual("1", 1) || // Multiple objects check !simpleRecusiveDeepEqual( { a:[1,2] }, { a:[1,2] }, { a:[1,2] } ) || // Ensure distinction between array and object (the following should fail) simpleRecusiveDeepEqual( [1963], { 0:1963 } ) || // Null strict checks simpleRecusiveDeepEqual( 0, null ) || simpleRecusiveDeepEqual( "", null ) || // Last "false" exists to make the various check above easy to comment in/out false ) { alert("FATAL ERROR: simpleRecusiveDeepEqual failed basic checks"); } else { //added this last line, for SO snippet alert on success alert("simpleRecusiveDeepEqual: Passed all checks, Yays!"); } })();