Porównanie obiektów w JavaScript [duplikat]

To pytanie ma już odpowiedź tutaj:

Jaki jest najlepszy sposób porównywania obiektów w JavaScript?

Przykład:

var user1 = {name : "nerd", org: "dev"};
var user2 = {name : "nerd", org: "dev"};
var eq = user1 == user2;
alert(eq); // gives false

Wiem, że dwa obiekty są równe, jeśli odnoszą się do dokładnie tego samego obiektu, ale czy istnieje sposób, aby sprawdzić, czy mają ten sam wartości atrybutów?

Następujący sposób działa dla mnie, ale czy jest to jedyna możliwość?

var eq = Object.toJSON(user1) == Object.toJSON(user2);
alert(eq); // gives true
Author: Matt, 2009-07-01

10 answers

Niestety nie ma doskonałego sposobu, chyba że użyjesz _proto_ rekurencyjnie i uzyskasz dostęp do wszystkich nieliczalnych właściwości, ale działa to tylko w Firefoksie.

Więc najlepsze, co mogę zrobić, to odgadnąć scenariusze użycia.


1) Szybki i ograniczony.

Działa, gdy masz proste obiekty w stylu JSON bez metod i węzłów DOM w środku:

 JSON.stringify(obj1) === JSON.stringify(obj2) 

Kolejność właściwości jest ważna, więc ta metoda zwróci false dla następujących obiekty:

 x = {a: 1, b: 2};
 y = {b: 2, a: 1};

2) powolne i bardziej ogólne.

Porównuje obiekty bez zagłębiania się w prototypy, następnie porównuje projekcje właściwości rekurencyjnie, a także porównuje konstruktory.

Jest to prawie poprawny algorytm:

function deepCompare () {
  var i, l, leftChain, rightChain;

  function compare2Objects (x, y) {
    var p;

    // remember that NaN === NaN returns false
    // and isNaN(undefined) returns true
    if (isNaN(x) && isNaN(y) && typeof x === 'number' && typeof y === 'number') {
         return true;
    }

    // Compare primitives and functions.     
    // Check if both arguments link to the same object.
    // Especially useful on the step where we compare prototypes
    if (x === y) {
        return true;
    }

    // Works in case when functions are created in constructor.
    // Comparing dates is a common scenario. Another built-ins?
    // We can even handle functions passed across iframes
    if ((typeof x === 'function' && typeof y === 'function') ||
       (x instanceof Date && y instanceof Date) ||
       (x instanceof RegExp && y instanceof RegExp) ||
       (x instanceof String && y instanceof String) ||
       (x instanceof Number && y instanceof Number)) {
        return x.toString() === y.toString();
    }

    // At last checking prototypes as good as we can
    if (!(x instanceof Object && y instanceof Object)) {
        return false;
    }

    if (x.isPrototypeOf(y) || y.isPrototypeOf(x)) {
        return false;
    }

    if (x.constructor !== y.constructor) {
        return false;
    }

    if (x.prototype !== y.prototype) {
        return false;
    }

    // Check for infinitive linking loops
    if (leftChain.indexOf(x) > -1 || rightChain.indexOf(y) > -1) {
         return false;
    }

    // Quick checking of one object being a subset of another.
    // todo: cache the structure of arguments[0] for performance
    for (p in y) {
        if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
            return false;
        }
        else if (typeof y[p] !== typeof x[p]) {
            return false;
        }
    }

    for (p in x) {
        if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
            return false;
        }
        else if (typeof y[p] !== typeof x[p]) {
            return false;
        }

        switch (typeof (x[p])) {
            case 'object':
            case 'function':

                leftChain.push(x);
                rightChain.push(y);

                if (!compare2Objects (x[p], y[p])) {
                    return false;
                }

                leftChain.pop();
                rightChain.pop();
                break;

            default:
                if (x[p] !== y[p]) {
                    return false;
                }
                break;
        }
    }

    return true;
  }

  if (arguments.length < 1) {
    return true; //Die silently? Don't know how to handle such case, please help...
    // throw "Need two or more arguments to compare";
  }

  for (i = 1, l = arguments.length; i < l; i++) {

      leftChain = []; //Todo: this can be cached
      rightChain = [];

      if (!compare2Objects(arguments[0], arguments[i])) {
          return false;
      }
  }

  return true;
}

Znane problemy (cóż, mają bardzo niski priorytet, prawdopodobnie nigdy ich nie zauważysz):

  • obiekty o innej strukturze prototypu, ale tej samej projekcji
  • funkcje mogą mieć identyczny tekst, ale Zobacz różne zamknięcia

Testy: testy są z Jak określić równość dla dwóch obiektów JavaScript?.

 956
Author: crazyx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:38

Oto moje skomentowane rozwiązanie w ES3 (szczegóły po kodzie):

Object.equals = function( x, y ) {
  if ( x === y ) return true;
    // if both x and y are null or undefined and exactly the same

  if ( ! ( x instanceof Object ) || ! ( y instanceof Object ) ) return false;
    // if they are not strictly equal, they both need to be Objects

  if ( x.constructor !== y.constructor ) return false;
    // they must have the exact same prototype chain, the closest we can do is
    // test there constructor.

  for ( var p in x ) {
    if ( ! x.hasOwnProperty( p ) ) continue;
      // other properties were tested using x.constructor === y.constructor

    if ( ! y.hasOwnProperty( p ) ) return false;
      // allows to compare x[ p ] and y[ p ] when set to undefined

    if ( x[ p ] === y[ p ] ) continue;
      // if they have the same strict value or identity then they are equal

    if ( typeof( x[ p ] ) !== "object" ) return false;
      // Numbers, Strings, Functions, Booleans must be strictly equal

    if ( ! Object.equals( x[ p ],  y[ p ] ) ) return false;
      // Objects and Arrays must be tested recursively
  }

  for ( p in y ) {
    if ( y.hasOwnProperty( p ) && ! x.hasOwnProperty( p ) ) return false;
      // allows x[ p ] to be set to undefined
  }
  return true;
}

Opracowując To rozwiązanie, przyjrzałem się szczególnie sprawnościom narożników, ale starałem się uzyskać proste rozwiązanie, które działa, Mam nadzieję, z pewną elegancją. JavaScript umożliwia zarówno null oraz undefined właściwości i obiekty mają prototypy łańcuchy może to prowadzić do bardzo różnych zachowań, jeśli nie jest zaznaczone.

Najpierw wybrałem extend obiekt zamiast obiekt.prototype, głównie dlatego, że null nie może być jednym z przedmiotów porównania i uważam, że null powinien być ważnym obiektem do porównania z innym. Istnieją również inne uzasadnione obawy zgłaszane przez inne osoby dotyczące rozszerzenia obiekt.prototype odnośnie możliwych skutków ubocznych na kod innych.

Należy zwrócić szczególną uwagę na możliwość, że JavaScript dopuszcza właściwości obiektu można ustawić na undefined, tzn. istnieją właściwości, których wartości są ustawiane na undefined. Powyższe rozwiązanie sprawdza, czy oba obiekty mają te same właściwości ustawione na undefined aby zgłosić równość. Można to osiągnąć tylko poprzez sprawdzenie istnienia właściwości za pomocą obiekt.hasOwnProperty( property_name ). Należy również pamiętać, że JSON.stringify() usuwa właściwości, które są ustawione na undefined, i dlatego porównania za pomocą tego formularza zignorują właściwości ustawione na wartość undefined.

Funkcje powinny być uważane za równe tylko wtedy, gdy mają ten sam odnośnik, a nie tylko ten sam kod, ponieważ nie uwzględniałoby to prototypu tych funkcji. Tak więc porównywanie ciągu kodu nie daje gwarancji, że mają ten sam prototypowy obiekt.

Dwa obiekty powinny mieć to samo łańcuch prototypów, nie tylko te same właściwości. Można to przetestować tylko w przeglądarce porównując konstruktor obu obiektów dla ścisłej równości. ECMAScript 5 pozwoliłby przetestować ich rzeczywisty prototyp przy użyciu obiekt.getPrototypeOf(). Niektóre przeglądarki internetowe oferują również właściwość __proto__, która robi to samo. Ewentualne udoskonalenie powyższego kodu pozwoliłoby na użycie jednej z tych metod kiedykolwiek dostępny.

Stosowanie ścisłych porównań jest tutaj najważniejsze, ponieważ 2 nie powinny być uważane za równe "2.0000", nor fałsz należy uznać za równe null, undefined, lub 0.

Względy wydajności skłaniają mnie do jak najszybszego porównania równości właściwości. Wtedy, tylko jeśli to się nie udało, poszukaj typeof te właściwości. Zwiększenie prędkości może być znaczące na dużych obiektach o wielu skalarnych właściwościach.

Nie więcej, że dwie pętle są wymagane, pierwsza do sprawdzenia właściwości z lewego obiektu, druga do sprawdzenia właściwości z prawego i sprawdzenia tylko istnienia (nie wartości), aby złapać te właściwości, które są zdefiniowane za pomocą undefined wartość.

Ogólnie ten kod obsługuje większość przypadków narożnych tylko w 16 liniach kodu (bez komentarzy).

Aktualizacja (8/13/2015). Zaimplementowałem lepszą wersję, ponieważ funkcja value_equals () , która jest szybsza, obsługuje poprawnie przypadki narożne, takie jak NaN i 0 różniące się od -0, opcjonalnie wymuszając kolejność właściwości obiektów i testując cykliczne odwołania, poparte ponad 100 automatycznych testów jako część pakietu testów projektu Toubkal.

 154
Author: Jean Vincent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-12 14:01:50
  Utils.compareObjects = function(o1, o2){
    for(var p in o1){
        if(o1.hasOwnProperty(p)){
            if(o1[p] !== o2[p]){
                return false;
            }
        }
    }
    for(var p in o2){
        if(o2.hasOwnProperty(p)){
            if(o1[p] !== o2[p]){
                return false;
            }
        }
    }
    return true;
};

Prosty sposób porównywania obiektów jednopoziomowych.

 22
Author: pincopallo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-02 15:27:20

Z pewnością nie jest to jedyny sposób-można prototypować metodę (w tym przypadku przeciwko obiektowi, ale na pewno nie sugerowałbym używania obiektu jako kodu aktywnego) do replikowania metod porównywania stylu C#/Java.

Edit, ponieważ ogólny przykład wydaje się być oczekiwany:

Object.prototype.equals = function(x)
{
    for(p in this)
    {
        switch(typeof(this[p]))
        {
            case 'object':
                if (!this[p].equals(x[p])) { return false }; break;
            case 'function':
                if (typeof(x[p])=='undefined' || (p != 'equals' && this[p].toString() != x[p].toString())) { return false; }; break;
            default:
                if (this[p] != x[p]) { return false; }
        }
    }

    for(p in x)
    {
        if(typeof(this[p])=='undefined') {return false;}
    }

    return true;
}

Zauważ, że testowanie metod za pomocą toString() jest absolutnie niewystarczająco dobre ale metoda, która byłaby akceptowalna, jest bardzo trudna ze względu na problem, że białe znaki mają znaczenie lub nie, nieważne metody synonimów i metody dające ten sam wynik przy różnych implementacjach. i problemy prototypowania przeciwko obiektowi w ogóle.

 20
Author: annakata,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-01 16:53:35

Poniższy algorytm zajmie się samorelacyjnymi strukturami danych, liczbami, łańcuchami, datami i oczywiście zwykłymi zagnieżdżonymi obiektami javascript:

Obiekty są uważane za równoważne, gdy

  • są dokładnie równe dla === (ciąg i liczba są rozpakowane jako pierwsze, aby upewnić się, że 42 jest równoważne Number(42))
  • albo są obie daty i mają tę samą valueOf()
  • lub oba są tego samego typu, a nie null i...
    • nie są obiektami i są równe dla == (liczby / ciągi / booleany)
    • lub ignorując właściwości z wartością undefined mają te same właściwości, z których wszystkie są uważane za równoważne rekurencyjnie.

Funkcje nie są uważane za identyczne przez tekst funkcji. Ten test jest niewystarczający, ponieważ funkcje mogą mieć różne zamknięcia. Funkcje są uważane za równe tylko wtedy, gdy === tak mówi (ale możesz łatwo rozszerzyć tę równoważną relację, jeśli wybierzesz zrobić).

Unika się pętli nieskończonych , potencjalnie spowodowanych kołowymi strukturami danych. Kiedy areEquivalent próbuje obalić równość i rekurencyjnie przekształca właściwości obiektu, śledzi obiekty, dla których potrzebne jest to porównanie podrzędne. Jeśli równość może być obalona, to pewna osiągalna ścieżka własności różni się między obiektami i wtedy musi istnieć Najkrótsza taka osiągalna ścieżka, a Najkrótsza osiągalna ścieżka nie może zawierać cykli obecnych w obu obiektach ścieżki; tzn. można przyjąć równość przy rekurencyjnym porównywaniu obiektów. Założenie jest przechowywane w właściwości areEquivalent_Eq_91_2_34, która jest usuwana po użyciu, ale jeśli Wykres obiektu zawiera już taką właściwość, zachowanie jest niezdefiniowane. Użycie takiej właściwości marker jest konieczne, ponieważ javascript nie obsługuje słowników wykorzystujących dowolne obiekty jako klucze.

function unwrapStringOrNumber(obj) {
    return (obj instanceof Number || obj instanceof String 
            ? obj.valueOf() 
            : obj);
}
function areEquivalent(a, b) {
    a = unwrapStringOrNumber(a);
    b = unwrapStringOrNumber(b);
    if (a === b) return true; //e.g. a and b both null
    if (a === null || b === null || typeof (a) !== typeof (b)) return false;
    if (a instanceof Date) 
        return b instanceof Date && a.valueOf() === b.valueOf();
    if (typeof (a) !== "object") 
        return a == b; //for boolean, number, string, xml

    var newA = (a.areEquivalent_Eq_91_2_34 === undefined),
        newB = (b.areEquivalent_Eq_91_2_34 === undefined);
    try {
        if (newA) a.areEquivalent_Eq_91_2_34 = [];
        else if (a.areEquivalent_Eq_91_2_34.some(
            function (other) { return other === b; })) return true;
        if (newB) b.areEquivalent_Eq_91_2_34 = [];
        else if (b.areEquivalent_Eq_91_2_34.some(
            function (other) { return other === a; })) return true;
        a.areEquivalent_Eq_91_2_34.push(b);
        b.areEquivalent_Eq_91_2_34.push(a);

        var tmp = {};
        for (var prop in a) 
            if(prop != "areEquivalent_Eq_91_2_34") 
                tmp[prop] = null;
        for (var prop in b) 
            if (prop != "areEquivalent_Eq_91_2_34") 
                tmp[prop] = null;

        for (var prop in tmp) 
            if (!areEquivalent(a[prop], b[prop]))
                return false;
        return true;
    } finally {
        if (newA) delete a.areEquivalent_Eq_91_2_34;
        if (newB) delete b.areEquivalent_Eq_91_2_34;
    }
}
 15
Author: Eamon Nerbonne,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-19 14:29:39

Napisałem ten fragment kodu do porównania obiektów i wydaje się, że działa. sprawdź twierdzenia:


function countProps(obj) {
    var count = 0;
    for (k in obj) {
        if (obj.hasOwnProperty(k)) {
            count++;
        }
    }
    return count;
};

function objectEquals(v1, v2) {

    if (typeof(v1) !== typeof(v2)) {
        return false;
    }

    if (typeof(v1) === "function") {
        return v1.toString() === v2.toString();
    }

    if (v1 instanceof Object && v2 instanceof Object) {
        if (countProps(v1) !== countProps(v2)) {
            return false;
        }
        var r = true;
        for (k in v1) {
            r = objectEquals(v1[k], v2[k]);
            if (!r) {
                return false;
            }
        }
        return true;
    } else {
        return v1 === v2;
    }
}

assert.isTrue(objectEquals(null,null));
assert.isFalse(objectEquals(null,undefined));

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

assert.isTrue(objectEquals(function(x){return x;},function(x){return x;}));
assert.isFalse(objectEquals(function(x){return x;},function(y){return y+2;}));
 11
Author: mhoms,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-03 19:56:50

Trochę zmodyfikowałem powyższy kod. dla mnie 0 != = false and null != = undefined . Jeśli nie potrzebujesz tak ścisłej kontroli usuń jeden "=" Zaloguj się " this [p]!= = x[p]" wewnątrz kodu.

Object.prototype.equals = function(x){
    for (var p in this) {
        if(typeof(this[p]) !== typeof(x[p])) return false;
        if((this[p]===null) !== (x[p]===null)) return false;
        switch (typeof(this[p])) {
            case 'undefined':
                if (typeof(x[p]) != 'undefined') return false;
                break;
            case 'object':
                if(this[p]!==null && x[p]!==null && (this[p].constructor.toString() !== x[p].constructor.toString() || !this[p].equals(x[p]))) return false;
                break;
            case 'function':
                if (p != 'equals' && this[p].toString() != x[p].toString()) return false;
                break;
            default:
                if (this[p] !== x[p]) return false;
        }
    }
    return true;
}

Następnie Przetestowałem go z kolejnymi obiektami:

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 f = {a: 'text', b:[1,0], f: function(){ this.f = this.b; }};
var g = {a: 'text', b:[1,0], f: function(){ this.f = this.b; }};
var h = {a: 'text', b:[1,0], f: function(){ this.a = this.b; }};
var i = {
    a: 'text',
    c: {
        b: [1, 0],
        f: function(){
            this.a = this.b;
        }
    }
};
var j = {
    a: 'text',
    c: {
        b: [1, 0],
        f: function(){
            this.a = this.b;
        }
    }
};
var k = {a: 'text', b: null};
var l = {a: 'text', b: undefined};

A = = B oczekiwana prawda; zwrócona prawda

A = = C oczekiwany false; zwrócony false

C = = D oczekiwany false; zwrócony false

A = = E oczekiwany false; zwrócony false

F = = g oczekiwana prawda; zwrócona prawda

H = = g oczekiwany false; zwrócony false

I = = J oczekiwana prawda; zwrócona prawda

D = = K oczekiwany false; zwrócony false

K = = L oczekiwano false; zwrócono false

 5
Author: Jevgeni Kiski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-29 11:19:16

Jeśli chcesz sprawdzić metody jawnie, możesz użyć metody.toSource () lub method.metody toString ().

 4
Author: Nicolas R,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-01 15:44:47

Oto moja wersja, prawie wszystko z tego wątku jest zintegrowane (to samo liczy się dla przypadków testowych):

Object.defineProperty(Object.prototype, "equals", {
    enumerable: false,
    value: function (obj) {
        var p;
        if (this === obj) {
            return true;
        }

        // some checks for native types first

        // function and sring
        if (typeof(this) === "function" || typeof(this) === "string" || this instanceof String) { 
            return this.toString() === obj.toString();
        }

        // number
        if (this instanceof Number || typeof(this) === "number") {
            if (obj instanceof Number || typeof(obj) === "number") {
                return this.valueOf() === obj.valueOf();
            }
            return false;
        }

        // null.equals(null) and undefined.equals(undefined) do not inherit from the 
        // Object.prototype so we can return false when they are passed as obj
        if (typeof(this) !== typeof(obj) || obj === null || typeof(obj) === "undefined") {
            return false;
        }

        function sort (o) {
            var result = {};

            if (typeof o !== "object") {
                return o;
            }

            Object.keys(o).sort().forEach(function (key) {
                result[key] = sort(o[key]);
            });

            return result;
        }

        if (typeof(this) === "object") {
            if (Array.isArray(this)) { // check on arrays
                return JSON.stringify(this) === JSON.stringify(obj);                
            } else { // anyway objects
                for (p in this) {
                    if (typeof(this[p]) !== typeof(obj[p])) {
                        return false;
                    }
                    if ((this[p] === null) !== (obj[p] === null)) {
                        return false;
                    }
                    switch (typeof(this[p])) {
                    case 'undefined':
                        if (typeof(obj[p]) !== 'undefined') {
                            return false;
                        }
                        break;
                    case 'object':
                        if (this[p] !== null 
                                && obj[p] !== null 
                                && (this[p].constructor.toString() !== obj[p].constructor.toString() 
                                        || !this[p].equals(obj[p]))) {
                            return false;
                        }
                        break;
                    case 'function':
                        if (this[p].toString() !== obj[p].toString()) {
                            return false;
                        }
                        break;
                    default:
                        if (this[p] !== obj[p]) {
                            return false;
                        }
                    }
                };

            }
        }

        // at least check them with JSON
        return JSON.stringify(sort(this)) === JSON.stringify(sort(obj));
    }
});

Oto mój test:

    assertFalse({}.equals(null));
    assertFalse({}.equals(undefined));

    assertTrue("String", "hi".equals("hi"));
    assertTrue("Number", new Number(5).equals(5));
    assertFalse("Number", new Number(5).equals(10));
    assertFalse("Number+String", 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}}));

    assertTrue("Function", (function(x){return x;}).equals(function(x){return x;}));
    assertFalse("Function", (function(x){return x;}).equals(function(y){return y+2;}));

    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 f = {a: 'text', b:[1,0], f: function(){ this.f = this.b; }};
    var g = {a: 'text', b:[1,0], f: function(){ this.f = this.b; }};
    var h = {a: 'text', b:[1,0], f: function(){ this.a = this.b; }};
    var i = {
        a: 'text',
        c: {
            b: [1, 0],
            f: function(){
                this.a = this.b;
            }
        }
    };
    var j = {
        a: 'text',
        c: {
            b: [1, 0],
            f: function(){
                this.a = this.b;
            }
        }
    };
    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(f.equals(g));
    assertFalse(h.equals(g));
    assertTrue(i.equals(j));
    assertFalse(d.equals(k));
    assertFalse(k.equals(l));
 4
Author: gossi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-02 11:39:24

Jeśli pracujesz bez biblioteki JSON, może to ci pomoże:

Object.prototype.equals = function(b) {
    var a = this;
    for(i in a) {
        if(typeof b[i] == 'undefined') {
            return false;
        }
        if(typeof b[i] == 'object') {
            if(!b[i].equals(a[i])) {
                return false;
            }
        }
        if(b[i] != a[i]) {
            return false;
        }
    }
    for(i in b) {
        if(typeof a[i] == 'undefined') {
            return false;
        }
        if(typeof a[i] == 'object') {
            if(!a[i].equals(b[i])) {
                return false;
            }
        }
        if(a[i] != b[i]) {
            return false;
        }
    }
    return true;
}

var a = {foo:'bar', bar: {blub:'bla'}};
var b = {foo:'bar', bar: {blub:'blob'}};
alert(a.equals(b)); // alert's a false
 3
Author: Samuel Weber,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-09 16:22:46