Pertanyaan Perbandingan objek dalam JavaScript [duplikat]


Pertanyaan ini sudah memiliki jawaban di sini:

Apa cara terbaik untuk membandingkan objek dalam JavaScript?

Contoh:

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

saya tahu itu dua benda sama jika mereka mengacu pada objek yang sama persis, tetapi apakah ada cara untuk memeriksa apakah mereka memiliki nilai atribut yang sama?

Cara berikut berfungsi untuk saya, tetapi apakah itu satu-satunya kemungkinan?

var eq = Object.toJSON(user1) == Object.toJSON(user2);
alert(eq); // gives true

785
2017-07-01 12:18


asal


Jawaban:


Sayangnya tidak ada cara sempurna, kecuali Anda menggunakannya _proto_ secara rekursif dan mengakses semua properti non-enumerable, tetapi ini hanya bekerja di Firefox.

Jadi yang terbaik yang bisa saya lakukan adalah menebak skenario penggunaan.


1) Cepat dan terbatas.

Berfungsi ketika Anda memiliki objek bergaya JSON sederhana tanpa metode dan node DOM di dalam:

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

ORDER dari properti IS PENTING, jadi metode ini akan mengembalikan false untuk objek berikut:

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

2) Lambat dan lebih umum.

Membandingkan objek tanpa menggali prototipe, kemudian membandingkan proyeksi properti secara rekursif, dan juga membandingkan konstruktor.

Ini algoritma yang hampir benar:

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

Masalah yang diketahui (baik, prioritasnya sangat rendah, mungkin Anda tidak akan pernah memperhatikannya):

  • objek dengan struktur prototipe yang berbeda tetapi proyeksi yang sama
  • fungsi mungkin memiliki teks yang identik tetapi merujuk pada penutupan yang berbeda

Tes: melewati tes berasal Bagaimana menentukan kesetaraan untuk dua objek JavaScript?.


923
2017-07-17 16:08



Berikut adalah solusi yang saya komentari di ES3 (detail yang mengerikan setelah kode):

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

Dalam mengembangkan solusi ini, saya mengambil pandangan khusus pada kasus-kasus sudut, efisiensi, namun mencoba menghasilkan solusi sederhana yang berhasil, semoga dengan beberapa keanggunan. JavaScript memungkinkan keduanya batal dan tidak terdefinisi properti dan benda-benda miliki rantai prototipe yang dapat menyebabkan perilaku yang sangat berbeda jika tidak dicentang.

Pertama saya memilih untuk memperpanjang Obyek dari pada Object.prototype, terutama karena batal tidak bisa menjadi salah satu objek perbandingan dan saya percaya itu batal harus menjadi objek yang valid untuk dibandingkan dengan yang lain. Ada juga kekhawatiran sah lainnya yang dicatat oleh orang lain mengenai perpanjangan Object.prototype mengenai kemungkinan efek samping pada kode orang lain.

Perhatian khusus harus diambil untuk menangani kemungkinan bahwa JavaScript memungkinkan properti objek dapat diatur ke tidak terdefinisi, yaitu ada properti yang nilainya ditetapkan tidak terdefinisi. Solusi di atas memverifikasi bahwa kedua objek memiliki properti yang sama diatur ke tidak terdefinisi untuk melaporkan kesetaraan. Ini hanya dapat dilakukan dengan memeriksa keberadaan properti menggunakan Object.hasOwnProperty (property_name). Juga perhatikan itu JSON.stringify () menghapus properti yang diatur ke tidak terdefinisi, dan karena itu perbandingan menggunakan formulir ini akan mengabaikan properti yang disetel ke nilai tidak terdefinisi.

Fungsi harus dianggap sama hanya jika mereka berbagi referensi yang sama, bukan hanya kode yang sama, karena ini tidak akan memperhitungkan fungsi prototipe ini. Jadi membandingkan string kode tidak bekerja untuk menjamin bahwa mereka memiliki objek prototipe yang sama.

Kedua benda harus memiliki yang sama rantai prototipe, bukan hanya properti yang sama. Ini hanya dapat diuji lintas-browser dengan membandingkan konstruktor dari kedua objek untuk kesetaraan yang ketat. ECMAScript 5 akan memungkinkan untuk menguji prototipe yang sebenarnya mereka gunakan Object.getPrototypeOf (). Beberapa browser web juga menawarkan __proto__ properti yang melakukan hal yang sama. Kemungkinan peningkatan kode di atas akan memungkinkan untuk menggunakan salah satu dari metode ini bila tersedia.

Penggunaan perbandingan yang ketat sangat penting di sini karena 2 seharusnya tidak dianggap sama "2,0000", juga Salah harus dianggap sama batal, tidak terdefinisi, atau 0.

Pertimbangan efisiensi membawa saya untuk membandingkan untuk kesetaraan properti sesegera mungkin. Kemudian, hanya jika itu gagal, carilah jenis properti ini. Peningkatan kecepatan dapat menjadi signifikan pada objek besar dengan banyak properti skalar.

Tidak ada lagi dua loop yang diperlukan, yang pertama untuk memeriksa properti dari objek kiri, yang kedua untuk memeriksa properti dari kanan dan memverifikasi hanya keberadaan (bukan nilai), untuk menangkap properti ini yang didefinisikan dengan tidak terdefinisi nilai.

Secara keseluruhan kode ini menangani sebagian besar kasus sudut hanya dalam 16 baris kode (tanpa komentar).

Perbarui (13/8/2015). Saya telah menerapkan versi yang lebih baik, sebagai fungsi value_equals () yang lebih cepat, menangani dengan benar kasus-kasus sudut seperti NaN dan 0 yang berbeda dari -0, opsional menegakkan pesanan sifat-sifat dan pengujian untuk referensi siklik, didukung oleh lebih dari 100 tes otomatis sebagai bagian dari Toubkal ruang uji proyek.


154
2017-07-15 22:21



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

Cara sederhana untuk membandingkan objek hanya SATU TINGKAT.


21
2018-05-02 15:27



Tentu bukan satu-satunya cara - Anda bisa membuat prototipe metode (melawan Objek di sini tapi saya pasti tidak akan menyarankan menggunakan Object untuk kode langsung) untuk meniru metode perbandingan gaya C # / Java.

Edit, karena contoh umum tampaknya diharapkan:

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

Perhatikan bahwa metode pengujian dengan toString () adalah benar-benar tidak cukup baik tetapi metode yang akan diterima sangat sulit karena masalah ruang putih memiliki makna atau tidak, tidak pernah memikirkan metode sinonim dan metode menghasilkan hasil yang sama dengan implementasi yang berbeda. Dan masalah prototyping terhadap Object secara umum.


19
2017-07-01 12:25



Algoritma berikut akan berurusan dengan struktur data referensi diri, angka, string, tanggal, dan tentu saja objek bertingkat javascript sederhana:

Objek dianggap setara saat

  • Mereka sama persis === (String dan Nomor dibuka terlebih dahulu untuk memastikan 42 setara dengan Number(42))
  • atau keduanya tanggal dan memiliki yang sama valueOf()
  • atau keduanya bertipe sama dan bukan null dan ...
    • mereka bukan benda dan sama per == (menangkap angka / string / boolean)
    • atau, mengabaikan properti dengan undefined nilai mereka memiliki sifat yang sama yang semuanya dianggap setara rekursif.

Fungsi tidak dianggap identik dengan teks fungsi. Tes ini tidak cukup karena fungsi mungkin memiliki perbedaan penutupan. Fungsi hanya dianggap sama jika === mengatakan demikian (tetapi Anda dapat dengan mudah memperpanjang hubungan yang setara jika Anda memilih untuk melakukannya).

Loop tak terbatas, berpotensi disebabkan oleh datastructures melingkar, dihindari. Kapan areEquivalent mencoba untuk menyangkal kesetaraan dan rekursif ke dalam properti objek untuk melakukannya, itu melacak objek yang sub-perbandingan ini diperlukan. Jika kesetaraan dapat dibantah, maka beberapa jalur properti yang dapat dicapai berbeda antara objek, dan kemudian harus ada jalur yang dapat dicapai terpendek, dan bahwa jalur terpendek yang terpendek tidak dapat berisi siklus yang ada di kedua jalur; yaitu tidak apa-apa untuk mengasumsikan kesetaraan saat membandingkan objek secara rekursif. Asumsinya disimpan di sebuah properti areEquivalent_Eq_91_2_34, yang dihapus setelah digunakan, tetapi jika grafik objek sudah mengandung properti seperti itu, perilaku tidak terdefinisi. Penggunaan properti penanda seperti itu diperlukan karena javascript tidak mendukung kamus menggunakan objek acak sebagai kunci.

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
2018-06-19 14:29



Saya menulis kode ini untuk perbandingan objek, dan tampaknya berhasil. periksa pernyataannya:


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
2017-10-03 11:01



Saya telah memodifikasi sedikit kode di atas. untuk saya 0! == salah dan null! == tidak terdefinisi. Jika Anda tidak perlu pemeriksaan yang ketat, hapus satu "=" masuk "ini [p]! == x [p]"di dalam kode.

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

Lalu saya telah mengujinya dengan objek-objek berikutnya:

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 yang diharapkan benar; kembali benar

a == c diduga salah; kembali salah

c == d dugaan salah; kembali salah

a == e dugaan salah; kembali salah

f == g yang diharapkan benar; kembali benar

h == g dugaan salah; kembali salah

i == j yang diharapkan benar; kembali benar

d == k diduga salah; kembali salah

k == saya memperkirakan salah; kembali salah


5
2018-04-29 09:17



jika Anda ingin memeriksa metode secara eksplisit, Anda dapat menggunakan metode method.toSource () atau method.toString ().


4
2017-07-01 15:44



Ini adalah versi saya, cukup banyak barang dari utas ini terintegrasi (jumlah yang sama untuk kasus uji coba):

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

Ini TestCase saya:

    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
2018-04-02 11:39



Jika Anda bekerja tanpa pustaka JSON, mungkin ini akan membantu Anda:

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
2018-03-09 10:38