Operator kesetaraan yang ketat akan memberi tahu Anda jika dua jenis objek sama. Namun, apakah ada cara untuk mengetahui apakah dua objek sama, mirip dengan nilai kode hash di Jawa?
Pertanyaan Stack Overflow Apakah ada fungsi hashCode dalam JavaScript? mirip dengan pertanyaan ini, tetapi membutuhkan jawaban yang lebih akademis. Skenario di atas menunjukkan mengapa perlu memilikinya, dan saya ingin tahu apakah ada solusi yang setara .
javascript
object
equals
hashcode
Komunitas
sumber
sumber
a.hashCode() == b.hashCode()
tidak tidak berarti bahwaa
sama denganb
. Ini kondisi yang diperlukan, bukan yang cukup.Jawaban:
Jawaban singkatnya
Jawaban sederhananya adalah: Tidak, tidak ada cara generik untuk menentukan bahwa suatu objek sama dengan yang lain dalam arti yang Anda maksud. Pengecualiannya adalah ketika Anda benar-benar memikirkan objek yang tidak bertuliskan.
Jawaban panjangnya
Konsepnya adalah metode Persamaan yang membandingkan dua contoh objek yang berbeda untuk menunjukkan apakah mereka sama pada tingkat nilai. Namun, tergantung pada tipe spesifik untuk menentukan bagaimana suatu
Equals
metode harus diimplementasikan. Perbandingan atribut berulang yang memiliki nilai primitif mungkin tidak cukup, mungkin ada atribut yang tidak dianggap sebagai bagian dari nilai objek. Sebagai contoh,Dalam kasus di atas,
c
tidak terlalu penting untuk menentukan apakah ada dua instance MyClass yang sama, hanyaa
danb
penting. Dalam beberapa kasusc
mungkin bervariasi di antara instance dan belum signifikan selama perbandingan.Catatan masalah ini berlaku ketika anggota mungkin juga merupakan contoh dari jenis dan masing-masing akan diminta untuk memiliki sarana untuk menentukan kesetaraan.
Hal-hal rumit selanjutnya adalah bahwa dalam JavaScript perbedaan antara data dan metode menjadi kabur.
Suatu objek dapat mereferensikan suatu metode yang disebut sebagai pengendali event, dan ini kemungkinan tidak akan dianggap sebagai bagian dari 'nilai negaranya'. Sedangkan objek lain mungkin ditugaskan fungsi yang melakukan perhitungan penting dan dengan demikian membuat instance ini berbeda dari yang lain hanya karena referensi fungsi yang berbeda.
Bagaimana dengan objek yang memiliki salah satu metode prototipe yang ada ditimpa oleh fungsi lain? Bisakah itu masih dianggap sama dengan contoh lain yang identik? Pertanyaan itu hanya dapat dijawab dalam setiap kasus khusus untuk setiap jenis.
Seperti yang dinyatakan sebelumnya, pengecualian akan menjadi objek yang sama sekali tidak bertipe. Dalam hal ini satu-satunya pilihan yang masuk akal adalah perbandingan iteratif dan rekursif dari masing-masing anggota. Bahkan kemudian kita harus bertanya apa 'nilai' suatu fungsi?
sumber
_.isEqual(obj1, obj2);
.equals
metode ini dengan benar tidak sepele, itulah sebabnya mengapa ada topik seperti itu yang didedikasikan di Jawa Efektif .javascript equality object
, mendapat tl; balasan dr, mengambil satu-liner dari komentar @chovy. terima kasihangular.equals
Mengapa menemukan kembali roda? Berikan Lodash mencoba. Ia memiliki sejumlah fungsi yang harus dimiliki seperti isEqual () .
Ini akan memaksa memeriksa setiap nilai kunci - seperti contoh lain di halaman ini - menggunakan ECMAScript 5 dan optimisasi asli jika mereka tersedia di browser.
Catatan: Sebelumnya jawaban ini merekomendasikan Underscore.js , tetapi lodash telah melakukan pekerjaan yang lebih baik untuk memperbaiki bug dan mengatasi masalah dengan konsistensi.
sumber
Operator kesetaraan default dalam JavaScript untuk Objek menghasilkan true ketika mereka merujuk ke lokasi yang sama dalam memori.
Jika Anda memerlukan operator kesetaraan yang berbeda, Anda perlu menambahkan
equals(other)
metode, atau sesuatu seperti itu ke kelas Anda dan spesifikasi domain masalah Anda akan menentukan apa artinya itu.Berikut ini contoh kartu bermain:
sumber
{x:1, y:2}
! =={y:2, x:1}
Jika Anda bekerja di AngularJS ,
angular.equals
fungsi akan menentukan apakah dua objek sama. Dalam penggunaan Ember.jsisEqual
.angular.equals
- Lihat dokumen atau sumber untuk lebih lanjut tentang metode ini. Itu juga membandingkan dalam pada array.isEqual
- Lihat dokumen atau sumber untuk lebih lanjut tentang metode ini. Itu tidak melakukan perbandingan yang mendalam pada array.sumber
Ini versi saya. Itu menggunakan fitur Object.keys baru yang diperkenalkan di ES5 dan ide / tes dari + , + dan + :
sumber
objectEquals([1,2,undefined],[1,2])
kembalitrue
objectEquals([1,2,3],{0:1,1:2,2:3})
juga mengembalikantrue
- misalnya tidak ada pemeriksaan tipe, hanya pemeriksaan kunci / nilai.objectEquals(new Date(1234),1234)
kembalitrue
Jika Anda menggunakan pustaka JSON, Anda bisa menyandikan setiap objek sebagai JSON, lalu membandingkan string yang dihasilkan untuk kesetaraan.
CATATAN: Meskipun jawaban ini akan berfungsi dalam banyak kasus, karena beberapa orang telah menunjukkan dalam komentar itu bermasalah karena berbagai alasan. Dalam hampir semua kasus, Anda ingin mencari solusi yang lebih kuat.
sumber
deepEqual
Implementasi fungsional pendek :Sunting : versi 2, menggunakan saran jib dan fungsi panah ES6:
sumber
reduce
denganevery
untuk menyederhanakan.Object.keys(x).every(key => deepEqual(x[key], y[key]))
.: (x === y)
dengan: (x === y && (x != null && y != null || x.constructor === y.constructor))
Apakah Anda mencoba menguji apakah dua objek itu sama? yaitu: propertinya sama?
Jika ini masalahnya, Anda mungkin telah memperhatikan situasi ini:
Anda mungkin harus melakukan sesuatu seperti ini:
Jelas fungsi itu bisa dilakukan dengan sedikit optimasi, dan kemampuan untuk melakukan pemeriksaan mendalam (untuk menangani objek bersarang:
var a = { foo : { fu : "bar" } }
tetapi Anda mendapatkan idenya.Seperti yang ditunjukkan FOR, Anda mungkin harus menyesuaikan ini untuk tujuan Anda sendiri, misalnya: kelas yang berbeda mungkin memiliki definisi "sama" yang berbeda. Jika Anda hanya bekerja dengan objek biasa, hal di atas mungkin sudah cukup, jika tidak,
MyClass.equals()
fungsi kustom mungkin merupakan cara untuk melakukannya.sumber
Jika Anda memiliki fungsi penyalinan dalam, Anda dapat menggunakan trik berikut untuk tetap menggunakan
JSON.stringify
sembari mencocokkan urutan properti:Demo: http://jsfiddle.net/CU3vb/3/
Alasan:
Karena properti dari
obj1
disalin ke klon satu per satu, pesanan mereka di klon akan dipertahankan. Dan ketika propertiobj2
disalin ke klon, karena properti yang sudah ada diobj1
hanya akan ditimpa, pesanan mereka di klon akan dipertahankan.sumber
Di Node.js, Anda bisa menggunakan aslinya
require("assert").deepStrictEqual
. Info lebih lanjut: http://nodejs.org/api/assert.htmlSebagai contoh:
Contoh lain yang mengembalikan
true
/false
bukannya mengembalikan kesalahan:sumber
Chai
memiliki fitur ini juga. Dalam hal ini, Anda akan menggunakan:var foo = { a: 1 }; var bar = { a: 1 }; expect(foo).to.deep.equal(bar); // true;
error.name
ke"AssertionError [ERR_ASSERTION]"
. Dalam hal ini, saya akan mengganti pernyataan if denganif (error.code === 'ERR_ASSERTION') {
.deepStrictEqual
adalah cara untuk pergi. Aku telah mengacaukan otakku mencoba mencari tahu mengapastrictEqual
tidak bekerja. Fantastis.Solusi paling sederhana dan logis untuk membandingkan semuanya Seperti Object, Array, String, Int ...
JSON.stringify({a: val1}) === JSON.stringify({a: val2})
catatan:
val1
danval2
dengan Obyek Andasumber
JSON.stringify
apakah pemesanan ulang alfabet? (Yang saya tidak dapat menemukan didokumentasikan .)Saya menggunakan
comparable
fungsi ini untuk menghasilkan salinan objek saya yang sebanding dengan JSON:Sangat berguna dalam tes (sebagian besar kerangka uji memiliki
is
fungsi). MisalnyaJika ada perbedaan, string dicatat, membuat perbedaan terlihat:
sumber
Inilah solusi di ES6 / ES2015 menggunakan pendekatan gaya fungsional:
demo tersedia di sini
sumber
Saya tidak tahu apakah ada orang yang memposting sesuatu yang mirip dengan ini, tapi inilah fungsi yang saya buat untuk memeriksa persamaan objek.
Selain itu, bersifat rekursif, sehingga juga dapat memeriksa kesetaraan yang mendalam, jika Anda menyebutnya demikian.
sumber
Bagi Anda yang menggunakan NodeJS, ada metode yang mudah dipanggil
isDeepStrictEqual
pada pustaka Util asli yang dapat mencapai ini.https://nodejs.org/api/util.html#util_util_isdeepstrictequal_val1_val2
sumber
ES6: Kode minimum yang bisa saya selesaikan, adalah ini. Ini melakukan perbandingan mendalam secara rekursif dengan merangkai semua objek, satu-satunya batasan adalah tidak ada metode atau simbol yang dibandingkan.
sumber
Anda dapat menggunakan
_.isEqual(obj1, obj2)
dari perpustakaan underscore.js.Berikut ini sebuah contoh:
Lihat dokumentasi resmi dari sini: http://underscorejs.org/#isEqual
sumber
Dengan asumsi bahwa urutan properti di objek tidak berubah.
JSON.stringify () bekerja untuk kedua jenis objek yang dalam dan tidak dalam, tidak terlalu yakin pada aspek kinerja:
sumber
Solusi sederhana untuk masalah ini yang tidak disadari banyak orang adalah dengan mengurutkan string JSON (per karakter). Ini juga biasanya lebih cepat daripada solusi lain yang disebutkan di sini:
Hal lain yang bermanfaat tentang metode ini adalah Anda dapat memfilter perbandingan dengan mengirimkan fungsi "replacer" ke fungsi JSON.stringify ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON / stringify # Example_of_using_replacer_parameter ). Berikut ini hanya akan membandingkan semua kunci objek yang diberi nama "derp":
sumber
areEqual({a: 'b'}, {b: 'a'})
mengertitrue
?Hanya ingin berkontribusi versi perbandingan objek saya menggunakan beberapa fitur es6. Itu tidak memperhitungkan pesanan. Setelah mengubah semua jika / selain menjadi ternary, saya datang dengan mengikuti:
sumber
Membutuhkan fungsi perbandingan objek yang lebih umum daripada yang telah diposting, saya memasak yang berikut ini. Kritik dihargai ...
sumber
Object.prototype
- dalam sebagian besar kasus tidak disarankan (tambahan muncul di semua untuk..di loop, misalnya). Mungkin mempertimbangkanObject.equals = function(aObj, bObj) {...}
?Jika Anda membandingkan objek JSON, Anda dapat menggunakan https://github.com/mirek/node-rus-diff
Pemakaian:
Jika dua objek berbeda,
{$rename:{...}, $unset:{...}, $set:{...}}
objek seperti MongoDB yang kompatibel dikembalikan.sumber
Saya menghadapi masalah yang sama dan memutuskan untuk menulis solusi sendiri. Tetapi karena saya ingin juga membandingkan Array dengan Objects dan sebaliknya, saya membuat solusi generik. Saya memutuskan untuk menambahkan fungsi ke prototipe, tetapi orang dapat dengan mudah menulis ulang mereka ke fungsi mandiri. Ini kodenya:
Algoritma ini dibagi menjadi dua bagian; Fungsi equals itu sendiri dan fungsi untuk menemukan indeks numerik properti dalam array / objek. Fungsi find hanya diperlukan karena indexof hanya menemukan angka dan string dan tidak ada objek.
Orang dapat menyebutnya seperti ini:
Fungsi mengembalikan benar atau salah, dalam hal ini benar. Algoritma juga memungkinkan perbandingan antara objek yang sangat kompleks:
Contoh atas akan mengembalikan true, bahkan properti memiliki urutan yang berbeda. Satu detail kecil yang harus diperhatikan: Kode ini juga memeriksa jenis dua variabel yang sama, jadi "3" tidak sama dengan 3.
sumber
Saya melihat jawaban kode spaghetti. Tanpa menggunakan lib pihak ketiga, ini sangat mudah.
Pertama-tama, urutkan kedua objek dengan memasukkan nama kunci mereka.
Kemudian cukup gunakan string untuk membandingkannya.
sumber
Saya akan menyarankan agar hashing atau serialisasi (seperti yang disarankan solusi JSON). Jika Anda perlu menguji apakah dua objek sama, maka Anda perlu mendefinisikan apa yang sama artinya. Bisa jadi semua anggota data di kedua objek cocok, atau bisa jadi lokasi memori harus cocok (artinya kedua variabel mereferensikan objek yang sama di memori), atau mungkin hanya satu anggota data di setiap objek yang harus cocok.
Baru-baru ini saya mengembangkan objek yang konstruktornya membuat id baru (mulai dari 1 dan bertambah 1) setiap kali sebuah instance dibuat. Objek ini memiliki fungsi isEqual yang membandingkan nilai id dengan nilai id dari objek lain dan mengembalikan true jika cocok.
Dalam hal ini saya mendefinisikan "sama" sebagai makna nilai-nilai id cocok. Mengingat bahwa setiap instance memiliki id unik ini dapat digunakan untuk menegakkan gagasan bahwa objek yang cocok juga menempati lokasi memori yang sama. Meskipun itu tidak perlu.
sumber
Ini berguna untuk mempertimbangkan dua objek yang sama jika mereka memiliki semua nilai yang sama untuk semua properti dan secara rekursif untuk semua objek dan array bersarang. Saya juga menganggap dua objek berikut ini sama:
Demikian pula, array dapat memiliki elemen "hilang" dan elemen tidak terdefinisi. Saya akan memperlakukan mereka yang sama juga:
Fungsi yang mengimplementasikan definisi persamaan ini:
Kode sumber (termasuk fungsi helper, generalType, dan uniqueArray): Unit Test dan Test Runner di sini .
sumber
Saya membuat asumsi berikut dengan fungsi ini:
Ini harus diperlakukan sebagai peragaan strategi sederhana.
sumber
Ini merupakan tambahan untuk semua hal di atas, bukan pengganti. Jika Anda perlu mempercepat objek membandingkan-dangkal tanpa perlu memeriksa kasus rekursif tambahan. Ini sebuah tembakan.
Ini membandingkan untuk: 1) Kesetaraan jumlah properti sendiri, 2) Kesetaraan nama kunci, 3) jika bCompareValues == true, Kesetaraan nilai properti yang sesuai dan tipenya (triple equality)
sumber
Untuk membandingkan kunci untuk instance objek kunci / nilai sederhana, saya menggunakan:
Setelah kunci dibandingkan,
for..in
loop tambahan sederhana sudah cukup.Kompleksitas adalah O (N * N) dengan N adalah jumlah kunci.
Saya harap / tebak objek yang saya tentukan tidak akan menampung lebih dari 1000 properti ...
sumber
Saya tahu ini agak lama, tetapi saya ingin menambahkan solusi yang saya temukan untuk masalah ini. Saya memiliki objek dan saya ingin tahu kapan datanya berubah. "sesuatu yang mirip dengan Object.observe" dan apa yang saya lakukan adalah:
Ini di sini dapat diduplikasi dan membuat set array lainnya untuk membandingkan nilai dan kunci. Ini sangat sederhana karena sekarang array dan akan mengembalikan false jika objek memiliki ukuran berbeda.
sumber
false
, karena array tidak membandingkan dengan nilai, mis[1,2] != [1,2]
.