嚴格的相等運算符將告訴您兩個對象類型是否相等。 可是,有沒有辦法判斷兩個對象是否相等, 就像 Java中的哈希碼值同樣 ? html
堆棧溢出問題JavaScript中是否存在某種hashCode函數? 與這個問題類似,但須要更多的學術答案。 上面的場景演示了爲何必需要有一個,而我想知道是否有任何等效的解決方案 。 git
若是您方便使用深層複製功能,則可使用如下技巧在匹配屬性順序時仍使用JSON.stringify
: angularjs
function equals(obj1, obj2) { function _equals(obj1, obj2) { return JSON.stringify(obj1) === JSON.stringify($.extend(true, {}, obj1, obj2)); } return _equals(obj1, obj2) && _equals(obj2, obj1); }
演示: http : //jsfiddle.net/CU3vb/3/ github
理由: ajax
因爲obj1
的屬性被一一複製到克隆,所以將保留它們在克隆中的順序。 而且,當將obj2
的屬性複製到克隆中時,因爲obj1
已經存在的屬性將被簡單地覆蓋,所以它們在克隆中的順序將得以保留。 api
這是個人版本。 它使用ES5中引入的Object.keys新功能以及+ , +和+的想法/測試: 數組
function objectEquals(x, y) { 'use strict'; if (x === null || x === undefined || y === null || y === undefined) { return x === y; } // after this just checking type of one would be enough if (x.constructor !== y.constructor) { return false; } // if they are functions, they should exactly refer to same one (because of closures) if (x instanceof Function) { return x === y; } // if they are regexps, they should exactly refer to same one (it is hard to better equality check on current ES) if (x instanceof RegExp) { return x === y; } if (x === y || x.valueOf() === y.valueOf()) { return true; } if (Array.isArray(x) && x.length !== y.length) { return false; } // if they are dates, they must had equal valueOf if (x instanceof Date) { return false; } // if they are strictly equal, they both need to be object at least if (!(x instanceof Object)) { return false; } if (!(y instanceof Object)) { return false; } // recursive object equality check var p = Object.keys(x); return Object.keys(y).every(function (i) { return p.indexOf(i) !== -1; }) && p.every(function (i) { return objectEquals(x[i], y[i]); }); } /////////////////////////////////////////////////////////////// /// The borrowed tests, run them by clicking "Run code snippet" /////////////////////////////////////////////////////////////// var printResult = function (x) { if (x) { document.write('<div style="color: green;">Passed</div>'); } else { document.write('<div style="color: red;">Failed</div>'); } }; var assert = { isTrue: function (x) { printResult(x); }, isFalse: function (x) { printResult(!x); } } assert.isTrue(objectEquals(null,null)); assert.isFalse(objectEquals(null,undefined)); assert.isFalse(objectEquals(/abc/, /abc/)); assert.isFalse(objectEquals(/abc/, /123/)); var r = /abc/; assert.isTrue(objectEquals(r, r)); assert.isTrue(objectEquals("hi","hi")); assert.isTrue(objectEquals(5,5)); assert.isFalse(objectEquals(5,10)); assert.isTrue(objectEquals([],[])); assert.isTrue(objectEquals([1,2],[1,2])); assert.isFalse(objectEquals([1,2],[2,1])); assert.isFalse(objectEquals([1,2],[1,2,3])); assert.isTrue(objectEquals({},{})); assert.isTrue(objectEquals({a:1,b:2},{a:1,b:2})); assert.isTrue(objectEquals({a:1,b:2},{b:2,a:1})); assert.isFalse(objectEquals({a:1,b:2},{a:1,b:3})); assert.isTrue(objectEquals({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}},{1:{name:"mhc",age:28}, 2:{name:"arb",age:26}})); assert.isFalse(objectEquals({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}},{1:{name:"mhc",age:28}, 2:{name:"arb",age:27}})); Object.prototype.equals = function (obj) { return objectEquals(this, obj); }; var assertFalse = assert.isFalse, assertTrue = assert.isTrue; assertFalse({}.equals(null)); assertFalse({}.equals(undefined)); assertTrue("hi".equals("hi")); assertTrue(new Number(5).equals(5)); assertFalse(new Number(5).equals(10)); assertFalse(new Number(1).equals("1")); assertTrue([].equals([])); assertTrue([1,2].equals([1,2])); assertFalse([1,2].equals([2,1])); assertFalse([1,2].equals([1,2,3])); assertTrue(new Date("2011-03-31").equals(new Date("2011-03-31"))); assertFalse(new Date("2011-03-31").equals(new Date("1970-01-01"))); assertTrue({}.equals({})); assertTrue({a:1,b:2}.equals({a:1,b:2})); assertTrue({a:1,b:2}.equals({b:2,a:1})); assertFalse({a:1,b:2}.equals({a:1,b:3})); assertTrue({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}}.equals({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}})); assertFalse({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}}.equals({1:{name:"mhc",age:28}, 2:{name:"arb",age:27}})); var a = {a: 'text', b:[0,1]}; var b = {a: 'text', b:[0,1]}; var c = {a: 'text', b: 0}; var d = {a: 'text', b: false}; var e = {a: 'text', b:[1,0]}; var i = { a: 'text', c: { b: [1, 0] } }; var j = { a: 'text', c: { b: [1, 0] } }; var k = {a: 'text', b: null}; var l = {a: 'text', b: undefined}; assertTrue(a.equals(b)); assertFalse(a.equals(c)); assertFalse(c.equals(d)); assertFalse(a.equals(e)); assertTrue(i.equals(j)); assertFalse(d.equals(k)); assertFalse(k.equals(l)); // from comments on stackoverflow post assert.isFalse(objectEquals([1, 2, undefined], [1, 2])); assert.isFalse(objectEquals([1, 2, 3], { 0: 1, 1: 2, 2: 3 })); assert.isFalse(objectEquals(new Date(1234), 1234)); // no two different function is equal really, they capture their context variables // so even if they have same toString(), they won't have same functionality var func = function (x) { return true; }; var func2 = function (x) { return true; }; assert.isTrue(objectEquals(func, func)); assert.isFalse(objectEquals(func, func2)); assert.isTrue(objectEquals({ a: { b: func } }, { a: { b: func } })); assert.isFalse(objectEquals({ a: { b: func } }, { a: { b: func2 } }));
我使用此函數進行如下假設: 瀏覽器
這應該被視爲簡單策略的演示。 ide
/** * Checks the equality of two objects that contain primitive values. (ie. no nested objects, functions, etc.) * @param {Object} object1 * @param {Object} object2 * @param {Boolean} [order_matters] Affects the return value of unordered objects. (ex. {a:1, b:2} and {b:2, a:1}). * @returns {Boolean} */ function isEqual( object1, object2, order_matters ) { var keys1 = Object.keys(object1), keys2 = Object.keys(object2), i, key; // Test 1: Same number of elements if( keys1.length != keys2.length ) { return false; } // If order doesn't matter isEqual({a:2, b:1}, {b:1, a:2}) should return true. // keys1 = Object.keys({a:2, b:1}) = ["a","b"]; // keys2 = Object.keys({b:1, a:2}) = ["b","a"]; // This is why we are sorting keys1 and keys2. if( !order_matters ) { keys1.sort(); keys2.sort(); } // Test 2: Same keys for( i = 0; i < keys1.length; i++ ) { if( keys1[i] != keys2[i] ) { return false; } } // Test 3: Values for( i = 0; i < keys1.length; i++ ) { key = keys1[i]; if( object1[key] != object2[key] ) { return false; } } return true; }
若是您使用的是AngularJS ,則angular.equals
函數將肯定兩個對象是否相等。 在Ember.js中,使用isEqual
。 函數
angular.equals
有關此方法的更多信息,請參見文檔或來源 。 它也對數組進行了深刻的比較。 isEqual
-查看文檔或源以得到更多關於這種方法。 它沒有對數組作深刻的比較。 var purple = [{"purple": "drank"}]; var drank = [{"purple": "drank"}]; if(angular.equals(purple, drank)) { document.write('got dat'); }
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
您是否要測試兩個對象是否相等? 即:它們的屬性是否相等?
若是是這種狀況,您可能已經注意到這種狀況:
var a = { foo : "bar" }; var b = { foo : "bar" }; alert (a == b ? "Equal" : "Not equal"); // "Not equal"
您可能須要執行如下操做:
function objectEquals(obj1, obj2) { for (var i in obj1) { if (obj1.hasOwnProperty(i)) { if (!obj2.hasOwnProperty(i)) return false; if (obj1[i] != obj2[i]) return false; } } for (var i in obj2) { if (obj2.hasOwnProperty(i)) { if (!obj1.hasOwnProperty(i)) return false; if (obj1[i] != obj2[i]) return false; } } return true; }
顯然,該功能能夠進行不少優化,而且能夠進行深度檢查(處理嵌套對象: var a = { foo : { fu : "bar" } }
)),可是您明白了。
正如FOR指出的那樣,您可能必須出於本身的目的對此進行調整,例如:不一樣的類可能具備不一樣的「等於」定義。 若是僅使用普通對象,則上面的內容就足夠了,不然,可使用自定義MyClass.equals()
函數。