كيفية تحديد المساواة بين اثنين جافا سكريبت الكائنات ؟

StackOverflow https://stackoverflow.com/questions/201183

سؤال

صارمة المساواة المشغل سوف أقول لكم إذا كان اثنين من وجوه أنواع متساوية.ومع ذلك, هل هناك طريقة لمعرفة إذا كان اثنين من الأشياء متساوية ، مثل الكثير من رمز التجزئة القيمة في جافا ؟

تجاوز سعة المكدس السؤال هل هناك أي نوع من hashCode وظيفة في جافا سكريبت ؟ يشبه هذا السؤال ، ولكن يتطلب المزيد من الأكاديمية الإجابة.السيناريو أعلاه يوضح لماذا سيكون من الضروري أن يكون أحد و أنا أتساءل إذا كان هناك أي أي ما يعادل الحل.

هل كانت مفيدة؟

المحلول

الجواب القصير

الجواب البسيط هو:لا يوجد عامة يعني أن تحديد كائن يساوي آخر بمعنى تعنيه.الاستثناء هو عندما كنت بدقة التفكير كائن يجري typeless.

الجواب طويلة

هذا المفهوم هو أن يساوي الأسلوب الذي يقارن بين اثنين من حالات مختلفة من كائن إلى الإشارة إلى ما إذا كانت متساوية في قيمة المستوى.ومع ذلك ، فمن يصل إلى نوع معين لتحديد كيف Equals طريقة ينبغي تنفيذها.تكرارية مقارنة بين سمات بدائية القيم قد لا يكون كافيا ، قد يكون هناك أيضا من الصفات التي لا تعتبر جزء من قيمة الكائن.على سبيل المثال ،

 function MyClass(a, b)
 {
     var c;
     this.getCLazy = function() {
         if (c === undefined) c = a * b // imagine * is really expensive
         return c;
     }
  }

في هذه الحالة المذكورة أعلاه ، c ليس من المهم تحديد ما إذا كان أي مثيلين من MyClass سواسية فقط a و b هامة.في بعض الحالات c قد تختلف بين الحالات و مع ذلك لا تكون كبيرة خلال المقارنة.

ملاحظة هذه المشكلة على الأعضاء أنفسهم أيضا حالات من نوع وكل هذه كلها يلزم أن يكون وسيلة لتحديد المساواة.

وما زاد الأمور تعقيدا هو أنه في جافا سكريبت التمييز بين البيانات و طريقة واضحة.

كائن قد مرجع طريقة هو أن يسمى معالج الحدث ، وهذا يحتمل أن لا تعتبر جزءا من قيمة الدولة'.في حين كائن آخر قد يكون تعيين الوظيفة التي يقوم هامة حساب و مما يجعل هذه الحالة مختلفة عن الآخرين لأنه ببساطة المراجع وظيفة مختلفة.

ماذا عن كائن واحد من القائمة النموذج أساليب تجاوزها من جانب آخر وظيفة ؟ يمكن أن لا تزال تعتبر متساوية إلى مثيل آخر أنه خلاف متطابقة ؟ هذا السؤال يمكن الإجابة عليه في كل حالة محددة لكل نوع.

كما ذكر في وقت سابق ، باستثناء بدقة typeless الكائن.في هذه الحالة الاختيار المنطقي الوحيد هو تكرارية و متكررة مقارنة بين كل الأعضاء.حتى ذلك الحين على المرء أن يسأل ما هي "القيمة" وظيفة ؟

نصائح أخرى

لماذا إعادة اختراع العجلة ؟ تعطي Lodash المحاولة.أنه يحتوي على عدد من الوظائف مثل isEqual().

_.isEqual(object, other);

وسوف القوة الغاشمة تحقق كل قيمة المفتاح - تماما مثل غيرها من الأمثلة على هذه الصفحة باستخدام ECMAScript 5 و الأم تحسينات إذا كانت متاحة في المتصفح.

ملاحظة:سابقا هذا الجواب الموصى بها Underscore.js, ولكن lodash وقد قامت بعمل أفضل من الحصول على البق الثابتة ومعالجة القضايا مع الاتساق.

الافتراضي المشغل المساواة في جافا سكريبت الكائنات ينتج الحقيقية عندما تشير إلى نفس الموقع في الذاكرة.

var x = {};
var y = {};
var z = x;

x === y; // => false
x === z; // => true

إذا كنت تحتاج إلى المساواة المشغل سوف تحتاج إلى إضافة equals(other) أسلوب أو شيء من هذا القبيل إلى فصول تفاصيل مشكلتك المجال سوف تحدد بالضبط ما يعنيه ذلك.

وهنا بطاقة اللعب على سبيل المثال:

function Card(rank, suit) {
  this.rank = rank;
  this.suit = suit;
  this.equals = function(other) {
     return other.rank == this.rank && other.suit == this.suit;
  };
}

var queenOfClubs = new Card(12, "C");
var kingOfSpades = new Card(13, "S");

queenOfClubs.equals(kingOfSpades); // => false
kingOfSpades.equals(new Card(13, "S")); // => true

إذا كنت تعمل في AngularJS, ، angular.equals وظيفة تحديد ما إذا كان اثنين من الأشياء متساوية.في Ember.js استخدام isEqual.

  • angular.equals - انظر مستندات أو المصدر لمزيد من المعلومات حول هذا الأسلوب.فإنه العميق مقارنة على المصفوفات أيضا.
  • Ember.js 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>

هذا هو الإصدار.هو استخدام جديدة الكائن.مفاتيح الميزة التي يتم تقديمها في ES5 و الأفكار/الاختبارات من +, + و +:

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 } }));

إذا كنت تستخدم سلمان المكتبة يمكنك ترميز كل كائن JSON, ثم قارن الناتج سلاسل من أجل المساواة.

var obj1={test:"value"};
var obj2={test:"value2"};

alert(JSON.encode(obj1)===JSON.encode(obj2));

ملاحظة:في حين أن هذا الجواب سوف تعمل في كثير من الحالات ، وقد أشار العديد من الناس في التعليقات انها مشكلة لمجموعة متنوعة من الأسباب.في كثير جدا من جميع الحالات سوف تحتاج إلى العثور على الحل أكثر قوة.

قصيرة الوظيفية deepEqual التنفيذ:

function deepEqual(x, y) {
  return (x && y && typeof x === 'object' && typeof y === 'object') ?
    (Object.keys(x).length === Object.keys(y).length) &&
      Object.keys(x).reduce(function(isEqual, key) {
        return isEqual && deepEqual(x[key], y[key]);
      }, true) : (x === y);
}

تحرير:الإصدار 2, باستخدام الذراع اقتراح ES6 السهم وظائف:

function deepEqual(x, y) {
  const ok = Object.keys, tx = typeof x, ty = typeof y;
  return x && y && tx === 'object' && tx === ty ? (
    ok(x).length === ok(y).length &&
      ok(x).every(key => deepEqual(x[key], y[key]))
  ) : (x === y);
}

إذا كان لديك نسخة عميق وظيفة في متناول اليد, يمكنك استخدام ما يلي خدعة لا يزال استخدام JSON.stringify بينما مطابقة النظام من خصائص:

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);
}

Demo: http://jsfiddle.net/CU3vb/3/

الأساس المنطقي:

منذ خصائص obj1 يتم نسخها إلى استنساخ واحد في استنساخ سيتم الحفاظ عليها.وعندما خصائص obj2 يتم نسخها إلى استنساخ منذ الخصائص الموجودة بالفعل في obj1 سوف تكون ببساطة الكتابة ، أوامرهم في استنساخ سيتم الحفاظ عليها.

هل تحاول اختبار ما إذا كان اثنين من الكائنات هي متساوية ؟ أي:خصائصها هي متساوية ؟

إذا كان هذا هو الحال, سوف وربما كنت قد لاحظت هذه الحالة:

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" } }) ولكن تحصل على هذه الفكرة.

كما أشار إلى ذلك, قد تضطر إلى التكيف مع هذه لأغراض الخاصة بك ، على سبيل المثال:فئات مختلفة قد يكون لها تعريفات مختلفة من "المساواة".إذا كنت تعمل فقط مع عادي الأشياء المذكورة أعلاه قد يكون كافيا وإلا مخصص MyClass.equals() وظيفة قد يكون وسيلة للذهاب.

أبسط و منطقي حلول مقارنة كل شيء مثل كائن, مجموعة, سلسلة, Int...

JSON.stringify({a: val1}) === JSON.stringify({a: val2})

ملاحظة:

  • تحتاج إلى استبدال val1و val2 مع وجوه الخاص بك
  • الكائن لديك لفرز(مفتاح) بشكل متكرر على جانبي الكائنات

في Node.js يمكنك استخدام الأصلي require("assert").deepEqual.مزيد من المعلومات:http://nodejs.org/api/assert.html

على سبيل المثال:

var assert = require("assert");
assert.deepEqual({a:1, b:2}, {a:1, b:3}); // will throw AssertionError

مثال آخر على أن يعود true / false بدلا من العودة الأخطاء:

var assert = require("assert");

function deepEqual(a, b) {
    try {
      assert.deepEqual(a, b);
    } catch (error) {
      if (error.name === "AssertionError") {
        return false;
      }
      throw error;
    }
    return true;
};

أنا استخدم هذا comparable وظيفة لإنتاج نسخ من كائنات JSON للمقارنة:

var comparable = o => (typeof o != 'object' || !o)? o :
  Object.keys(o).sort().reduce((c, key) => (c[key] = comparable(o[key]), c), {});

// Demo:

var a = { a: 1, c: 4, b: [2, 3], d: { e: '5', f: null } };
var b = { b: [2, 3], c: 4, d: { f: null, e: '5' }, a: 1 };

console.log(JSON.stringify(comparable(a)));
console.log(JSON.stringify(comparable(b)));
console.log(JSON.stringify(comparable(a)) == JSON.stringify(comparable(b)));
<div id="div"></div>

تأتي في متناول اليدين في الاختبارات (معظم اختبار أطر لها is وظيفة).E. g.

is(JSON.stringify(comparable(x)), JSON.stringify(comparable(y)), 'x must match y');

إذا الفرق هو القبض, سلاسل الحصول على تسجيل, صنع الخلافات spottable:

x must match y
got      {"a":1,"b":{"0":2,"1":3},"c":7,"d":{"e":"5","f":null}},
expected {"a":1,"b":{"0":2,"1":3},"c":4,"d":{"e":"5","f":null}}.

ها هو الحل في ES6/ES2015 باستخدام وظيفية-نهج أسلوب:

const typeOf = x => 
  ({}).toString
      .call(x)
      .match(/\[object (\w+)\]/)[1]

function areSimilar(a, b) {
  const everyKey = f => Object.keys(a).every(f)

  switch(typeOf(a)) {
    case 'Array':
      return a.length === b.length &&
        everyKey(k => areSimilar(a.sort()[k], b.sort()[k]));
    case 'Object':
      return Object.keys(a).length === Object.keys(b).length &&
        everyKey(k => areSimilar(a[k], b[k]));
    default:
      return a === b;
  }
}

العرض متاح هنا

أنا لا أعرف إذا كان أي شخص نشر أي شيء مماثل لهذا, ولكن هنا وظيفة جعلت للتحقق من وجوه المساواة.

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;
}

كما انها متكررة, لذلك يمكن أيضا التحقق العميق بين الجنسين ، إذا كان هذا ما تسمونه.

يمكنك استخدام _.isEqual(obj1, obj2) من underscore.js المكتبة.

هنا مثال:

var stooge = {name: 'moe', luckyNumbers: [13, 27, 34]};
var clone  = {name: 'moe', luckyNumbers: [13, 27, 34]};
stooge == clone;
=> false
_.isEqual(stooge, clone);
=> true

انظر الوثائق الرسمية من هنا: http://underscorejs.org/#isEqual

حل بسيط لهذه المشكلة أن الكثير من الناس لا يدركون أن نوع سلمان السلاسل (في) حرف.وهذا هو أيضا عادة ما تكون أسرع من غيرها من الحلول المذكورة هنا:

function areEqual(obj1, obj2) {
    var a = JSON.stringify(obj1), b = JSON.stringify(obj2);
    if (!a) a = '';
    if (!b) b = '';
    return (a.split('').sort().join('') == b.split('').sort().join(''));
}

آخر شيء مفيد حول هذا الأسلوب يمكنك تصفية المقارنات عن طريق تمرير "بديل" وظيفة سلمان.stringify وظائف (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#Example_of_using_replacer_parameter).التالية فقط قارن جميع الكائنات مفاتيح اسمه "درب":

function areEqual(obj1, obj2, filter) {
    var a = JSON.stringify(obj1, filter), b = JSON.stringify(obj2, filter);
    if (!a) a = '';
    if (!b) b = '';
    return (a.split('').sort().join('') == b.split('').sort().join(''));
}
var equal = areEqual(obj1, obj2, function(key, value) {
    return (key === 'derp') ? value : undefined;
});

أنصحك بعدم تجزئة أو التسلسل (مثل سلمان الحل أقترح).إذا كنت بحاجة إلى اختبار ما إذا كان اثنين من الأشياء متساوية ، ثم تحتاج إلى تحديد ما يساوي يعني.يمكن أن يكون جميع أعضاء البيانات في كل مباراة الأشياء, أو أنه يمكن أن يكون يجب أن مواقع الذاكرة مباراة (يعني كل المتغيرات مرجعية نفس الكائن في الذاكرة) ، أو قد يكون ذلك بيانات واحدة فقط الأعضاء في كل كائن يجب أن تتطابق.

مؤخرا أنا وضعت كائن الذين منشئ إنشاء معرف جديد (بدءا من 1 و تزايد بنسبة 1) في كل مرة يتم إنشاء مثيل.هذا الكائن يحتوي على isEqual وظيفة أن يقارن هذا معرف القيمة مع قيمة معرف كائن آخر و إرجاع true إذا كانت تطابق.

في هذه الحالة تعريف "المساواة" يعني معرف القيم المباراة.نظرا إلى أن كل حالة لها هوية فريدة من نوعها يمكن أن تستخدم لفرض فكرة أن الكائنات مطابقة أيضا تحتل نفس موقع الذاكرة.على الرغم من أن هذا ليس ضروريا.

الحاجة إلى المزيد من generic كائن وظيفة مقارنة مما كان نشرها طبخت التالية.نقد تقدير...

Object.prototype.equals = function(iObj) {
  if (this.constructor !== iObj.constructor)
    return false;
  var aMemberCount = 0;
  for (var a in this) {
    if (!this.hasOwnProperty(a))
      continue;
    if (typeof this[a] === 'object' && typeof iObj[a] === 'object' ? !this[a].equals(iObj[a]) : this[a] !== iObj[a])
      return false;
    ++aMemberCount;
  }
  for (var a in iObj)
    if (iObj.hasOwnProperty(a))
      --aMemberCount;
  return aMemberCount ? false : true;
}

إذا كنت مقارنة كائنات JSON يمكنك استخدام https://github.com/mirek/node-rus-diff

npm install rus-diff

الاستخدام:

a = {foo:{bar:1}}
b = {foo:{bar:1}}
c = {foo:{bar:2}}

var rusDiff = require('rus-diff').rusDiff

console.log(rusDiff(a, b)) // -> false, meaning a and b are equal
console.log(rusDiff(a, c)) // -> { '$set': { 'foo.bar': 2 } }

إذا اثنين من كائنات مختلفة, MongoDB متوافق {$rename:{...}, $unset:{...}, $set:{...}} كما يتم إرجاع كائن.

أنا واجهت نفس المشكلة و deccided أن أكتب بلدي الحل.ولكن لأنني أريد أيضا مقارنة المصفوفات مع الكائنات والعكس بالعكس, أنا وضعت حل العامة.قررت لإضافة وظائف إلى النموذج ، ولكن يمكن للمرء بسهولة إعادة كتابة لهم مستقل الوظائف.هنا هو رمز:

Array.prototype.equals = Object.prototype.equals = function(b) {
    var ar = JSON.parse(JSON.stringify(b));
    var err = false;
    for(var key in this) {
        if(this.hasOwnProperty(key)) {
            var found = ar.find(this[key]);
            if(found > -1) {
                if(Object.prototype.toString.call(ar) === "[object Object]") {
                    delete ar[Object.keys(ar)[found]];
                }
                else {
                    ar.splice(found, 1);
                }
            }
            else {
                err = true;
                break;
            }
        }
    };
    if(Object.keys(ar).length > 0 || err) {
        return false;
    }
    return true;
}

Array.prototype.find = Object.prototype.find = function(v) {
    var f = -1;
    for(var i in this) {
        if(this.hasOwnProperty(i)) {
            if(Object.prototype.toString.call(this[i]) === "[object Array]" || Object.prototype.toString.call(this[i]) === "[object Object]") {
                if(this[i].equals(v)) {
                    f = (typeof(i) == "number") ? i : Object.keys(this).indexOf(i);
                }
            }
            else if(this[i] === v) {
                f = (typeof(i) == "number") ? i : Object.keys(this).indexOf(i);
            }
        }
    }
    return f;
}

هذه الخوارزمية هي تنقسم إلى قسمين ؛ يساوي وظيفة في حد ذاته وظيفة للعثور على مؤشر رقمي من الممتلكات في مجموعة / الكائن.العثور على وظيفة هو فقط في حاجة لأن indexof فقط يجد الأرقام و سلاسل و لا الأشياء .

واحد يمكن أن يطلق عليه مثل هذا:

({a: 1, b: "h"}).equals({a: 1, b: "h"});

وظيفة إما بإرجاع true أو false ، في هذه الحالة صحيحا.الخوارزمية als يسمح المقارنة بين معقدة جدا الكائنات:

({a: 1, b: "hello", c: ["w", "o", "r", "l", "d", {answer1: "should be", answer2: true}]}).equals({b: "hello", a: 1, c: ["w", "d", "o", "r", {answer1: "should be", answer2: true}, "l"]})

العليا المثال العودة الحقيقية, حتى ثو خصائص مختلفة الطلب.أحد التفاصيل الصغيرة للبحث عن:هذا الرمز أيضا بالتحقق من نفس النوع اثنين من المتغيرات ، لذلك "3" ليس هو نفس 3.

أردت فقط أن تسهم لي نسخة من الكائنات مقارنة الاستفادة من بعض الميزات es6.لأنها لا تأخذ الأمر بعين الاعتبار.بعد تحويل جميع إذا/آخر إلى الثلاثي لقد جاء التالية:

function areEqual(obj1, obj2) {

    return Object.keys(obj1).every(key => {

            return obj2.hasOwnProperty(key) ?
                typeof obj1[key] === 'object' ?
                    areEqual(obj1[key], obj2[key]) :
                obj1[key] === obj2[key] :
                false;

        }
    )
}

فإنه من المفيد النظر في اثنين من الأجسام متساوية إذا كان لديهم كل نفس القيم على جميع خصائص و بشكل متكرر لجميع الكائنات المتداخلة و المصفوفات.أنا أيضا النظر فيما يلي اثنين من الأجسام متساوية:

var a = {p1: 1};
var b = {p1: 1, p2: undefined};

وبالمثل ، المصفوفات يمكن أن يكون "في عداد المفقودين" عناصر غير العناصر.أود أن علاج تلك نفسها كذلك:

var c = [1, 2];
var d = [1, 2, undefined];

الوظيفة التي تطبق هذا التعريف من المساواة:

function isEqual(a, b) {
    if (a === b) {
        return true;
    }

    if (generalType(a) != generalType(b)) {
        return false;
    }

    if (a == b) {
        return true;
    }

    if (typeof a != 'object') {
        return false;
    }

    // null != {}
    if (a instanceof Object != b instanceof Object) {
        return false;
    }

    if (a instanceof Date || b instanceof Date) {
        if (a instanceof Date != b instanceof Date ||
            a.getTime() != b.getTime()) {
            return false;
        }
    }

    var allKeys = [].concat(keys(a), keys(b));
    uniqueArray(allKeys);

    for (var i = 0; i < allKeys.length; i++) {
        var prop = allKeys[i];
        if (!isEqual(a[prop], b[prop])) {
            return false;
        }
    }
    return true;
}

التعليمات البرمجية المصدر (بما في ذلك وظائف المساعد, generalType و uniqueArray):اختبار الوحدة و اختبار عداء هنا.

أنا جعل الافتراضات التالية مع هذه الوظيفة:

  1. يمكنك التحكم في الكائنات تقارنها و لديك فقط بدائية القيم (ie.لا الكائنات المتداخلة ، وظائف ، إلخ.).
  2. المتصفح يدعم الكائن.مفاتيح.

هذا وينبغي أن تعامل على أنها مظاهرة من استراتيجية بسيطة.

/**
 * 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;
}

هذا بالإضافة إلى كل ما سبق ، ليس بديل.إذا كنت بحاجة إلى الصيام الضحلة-قارن الأشياء من دون حاجة إلى تحقق إضافية متكررة الحالات.هنا هو لقطة.

ويقارن هذا من أجل:1) المساواة في عدد من الخصائص ، 2) المساواة الرئيسية أسماء 3) إذا bCompareValues == الحقيقية والمساواة في المقابلة الملكية القيم وأنواعها (الثلاثي بين الجنسين)

var shallowCompareObjects = function(o1, o2, bCompareValues) {
    var s, 
        n1 = 0,
        n2 = 0,
        b  = true;

    for (s in o1) { n1 ++; }
    for (s in o2) { 
        if (!o1.hasOwnProperty(s)) {
            b = false;
            break;
        }
        if (bCompareValues && o1[s] !== o2[s]) {
            b = false;
            break;
        }
        n2 ++;
    }
    return b && n1 == n2;
}

لمقارنة مفاتيح بسيطة أزواج مفتاح/قيمة الكائن الحالات يمكنني استخدام:

function compareKeys(r1, r2) {
    var nloops = 0, score = 0;
    for(k1 in r1) {
        for(k2 in r2) {
            nloops++;
            if(k1 == k2)
                score++; 
        }
    }
    return nloops == (score * score);
};

مرة واحدة مفاتيح مقارنة بسيطة إضافية for..in حلقة غير كافية.

تعقيد O(N*N) N هو عدد المفاتيح.

وآمل/تخمين الأشياء أحدد لن تصمد أكثر من 1000 خصائص...

أعرف أن هذا هو قليلا من العمر ، ولكن أود أن أضيف الحل الذي جئت مع هذه المشكلة.لدي موضوع أريد أن أعرف عند تغيير البيانات."شيئا من هذا القبيل إلى الكائن.مراقبة" و ما فعلته كان:

function checkObjects(obj,obj2){
   var values = [];
   var keys = [];
   keys = Object.keys(obj);
   keys.forEach(function(key){
      values.push(key);
   });
   var values2 = [];
   var keys2 = [];
   keys2 = Object.keys(obj2);
   keys2.forEach(function(key){
      values2.push(key);
   });
   return (values == values2 && keys == keys2)
}

هذا يمكن أن تتكرر وخلق مجموعة أخرى من المصفوفات لمقارنة القيم والمفاتيح.وهو بسيط جدا لأنهم الآن المصفوفات و سوف return false إذا كائنات مختلفة الأحجام.

سحب من مكتبتي الشخصية ، والتي يمكنني استخدام بلدي العمل مرارا وتكرارا.الدالة التالية هي مخففة العودية العميق متساوية ، لا تحقق

  • فئة المساواة
  • ورثت القيم
  • قيم المساواة التامة

أنا أساسا استخدام هذا الاختيار إذا كنت تحصل على المساواة في الردود ضد مختلف API التنفيذ.حيث تنفيذ الفرق (مثل سلسلة مقابل عدد) إضافية القيم null, يمكن أن تحدث.

تنفيذها بسيط جدا و قصيرة (إن جميع التعليقات يتم خلع)

/** 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!");
	}
})();

هنا هو نسخة من stringify الحيلة التي هي أقل الكتابة ويعمل في الكثير من الحالات تافهة البيانات JSON المقارنات.

var obj1Fingerprint = JSON.stringify(obj1).replace(/\{|\}/g,'').split(',').sort().join(',');
var obj2Fingerprint = JSON.stringify(obj2).replace(/\{|\}/g,'').split(',').sort().join(',');
if ( obj1Fingerprint === obj2Fingerprint) { ... } else { ... }

أرى السباغيتي رمز إجابات.دون استخدام أي طرف ثالث يبس ، هذا من السهل جدا.

أولا فرز اثنين من الكائنات عن طريق مفتاح الرئيسية أسماء.

let objectOne = { hey, you }
let objectTwo = { you, hey }

// If you really wanted you could make this recursive for deep sort.
const sortObjectByKeyname = (objectToSort) => {
    return Object.keys(objectToSort).sort().reduce((r, k) => (r[k] = objectToSort[k], r), {});
}

let objectOne = sortObjectByKeyname(objectOne)
let objectTwo = sortObjectByKeyname(objectTwo)

ثم ببساطة استخدام سلسلة المقارنة بينها.

JSON.stringify(objectOne) === JSON.stringify(objectTwo)

لأولئك منكم استخدام NodeJS, وهناك طريقة مريحة يسمى isDeepStrictEqual على الأم Util المكتبة التي يمكن تحقيق هذا.

const util = require('util');

const foo = {
  hey: "ho",
  lets: "go"
}

const bar = {
  hey: "ho",
  lets: "go"
}

foo == bar // false
util.isDeepStrictEqual(foo, bar) // true

https://nodejs.org/api/util.html#util_util_isdeepstrictequal_val1_val2

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top