Jika saya memiliki referensi ke suatu objek:
var test = {};
yang berpotensi (tetapi tidak segera) memiliki objek bersarang, seperti:
{level1: {level2: {level3: "level3"}}};
Apa cara terbaik untuk memeriksa keberadaan properti di objek bersarang mendalam?
alert(test.level1);
hasil undefined
, tetapi alert(test.level1.level2.level3);
gagal.
Saya sedang melakukan sesuatu seperti ini:
if(test.level1 && test.level1.level2 && test.level1.level2.level3) {
alert(test.level1.level2.level3);
}
tapi saya bertanya-tanya apakah ada cara yang lebih baik.
javascript
object
properties
nested
pengguna113716
sumber
sumber
Jawaban:
Anda harus melakukannya langkah demi langkah jika Anda tidak menginginkannya
TypeError
karena jika salah satu anggota adalahnull
atauundefined
, dan Anda mencoba mengakses anggota, pengecualian akan dilemparkan.Anda bisa hanya
catch
pengecualian, atau membuat fungsi untuk menguji keberadaan beberapa level, seperti ini:ES6 PEMBARUAN:
Ini adalah versi yang lebih pendek dari fungsi aslinya, menggunakan fitur ES6 dan rekursi (ini juga dalam bentuk panggilan ekor yang tepat ):
Namun, jika Anda ingin mendapatkan nilai properti bersarang dan tidak hanya memeriksa keberadaannya, berikut ini adalah fungsi satu-baris yang sederhana:
Fungsi di atas memungkinkan Anda untuk mendapatkan nilai properti bersarang, jika tidak akan kembali
undefined
.UPDATE 2019-10-17:
The chaining usulan opsional mencapai Tahap 3 pada proses komite ECMAScript , ini akan memungkinkan Anda untuk dengan aman akses properti sangat bersarang, dengan menggunakan token
?.
, yang baru chaining Operator opsional :Jika salah satu level yang diakses adalah
null
atauundefined
ekspresi akan diselesaikanundefined
dengan sendirinya.Proposal juga memungkinkan Anda untuk menangani panggilan metode dengan aman:
Ekspresi di atas akan menghasilkan
undefined
jikaobj
,obj.level1
atauobj.level1.method
yangnull
atauundefined
, jika tidak maka akan memanggil fungsi.Anda dapat mulai bermain dengan fitur ini dengan Babel menggunakan plugin chaining opsional .Sejak Babel 7.8.0 , ES2020 didukung secara default
Lihat contoh ini di Babel REPL.
🎉🎉UPDATE: Desember 2019 🎉🎉
Proposal perangkaian opsional akhirnya mencapai Tahap 4 pada pertemuan komite TC39 Desember 2019. Ini berarti fitur ini akan menjadi bagian dari ECMAScript 2020 Standard.
sumber
arguments
sebenarnya bukan array.Array.prototype.slice.call(arguments)
mengubahnya menjadi array formal. Belajarvar obj = arguments[0];
dan mulai darivar i = 1
daripada menyalinarguments
objekargs
deklarasi variabel dapat dihapus dan dan...args
dapat digunakan sebagai argumen kedua untukcheckNested
metode ini. developer.mozilla.org/en/docs/Web/JavaScript/Reference/…Berikut adalah pola yang saya ambil dari Oliver Steele :
Sebenarnya seluruh artikel itu adalah diskusi tentang bagaimana Anda bisa melakukan ini dalam javascript. Ia memilih menggunakan sintaks di atas (yang tidak terlalu sulit untuk dibaca setelah Anda terbiasa) sebagai ungkapan.
sumber
(test || {})
adalah bahwa jika tes tidak ditentukan, maka Anda lakukan({}.level1 || {})
. Tentu saja,{}.level1
tidak terdefinisi, jadi itu berarti Anda lakukan{}.level2
, dan sebagainya.test
tidak dideklarasikan, akan ada ReferenceError , tapi itu tidak masalah, karena jika tidak dideklarasikan, ada bug yang harus diperbaiki, jadi kesalahannya adalah hal yang baik.if(test.level1 && test.level1.level2 && test.level1.level2.level3)
Memperbarui
Sepertinya lodash telah menambahkan
_.get
untuk semua properti bersarang Anda mendapatkan kebutuhan.https://lodash.com/docs#get
Jawaban sebelumnya
pengguna lodash dapat menikmati lodash.contrib yang memiliki beberapa metode yang mengurangi masalah ini .
getPath
Tanda tangan:
_.getPath(obj:Object, ks:String|Array)
Mendapat nilai pada kedalaman apa pun di objek bersarang berdasarkan jalur yang dijelaskan oleh tombol yang diberikan. Kunci dapat diberikan sebagai array atau sebagai string yang dipisahkan titik. Kembali
undefined
jika jalur tidak dapat dicapai.sumber
function isPathDefined(object, path) { return typeof _.getPath(object, path) !== 'undefined'; }
_.get(countries, 'greece.sparta.playwright', 'default'); // → 'default' _.has(countries, 'greece.spart.playwright') // → false
var url = _.get(e, 'currentTarget.myurl', null) || _.get(e, 'currentTarget.attributes.myurl.nodeValue', null) || null
Saya telah melakukan tes kinerja (terima kasih cdMinix untuk menambahkan lodash) pada beberapa saran yang diajukan untuk pertanyaan ini dengan hasil yang tercantum di bawah ini.
Obyek Bungkus (oleh Oliver Steele) - 34% - tercepat
Solusi asli (disarankan dalam pertanyaan) - 45%
checkNested - 50%
get_if_exist - 52%
validChain - 54%
objHasKeys - 63%
nestedPropertyExists - 69%
_.get - 72%
deeptest - 86%
badut sedih - 100% - paling lambat
sumber
_.get()
? bagaimana performansnya dibandingkan dengan jawaban-jawaban itu?reduce
atautry/catch
keluar dari kenyamanan.try { test.level1.level2.level3 } catch (e) { // some logger e }
Anda dapat membaca properti objek di kedalaman apapun, jika Anda menangani nama seperti string:
't.level1.level2.level3'
.Ini mengembalikan
undefined
jika salah satu segmen adalahundefined
.sumber
Jika Anda mengkode dalam lingkungan ES6 (atau menggunakan 6to5 ) maka Anda dapat memanfaatkan sintaks fungsi panah :
Mengenai kinerja, tidak ada penalti kinerja untuk menggunakan
try..catch
blok jika properti diatur. Ada dampak kinerja jika properti tidak disetel.Pertimbangkan hanya menggunakan
_.has
:sumber
try-catch
pendekatannya adalah jawaban terbaik. Ada perbedaan filosofis antara permintaan objek untuk tipenya, dan dengan asumsi API ada dan gagal jika tidak. Yang terakhir lebih tepat dalam bahasa yang diketik longgar. Lihat stackoverflow.com/a/408305/2419669 . Thetry-catch
Pendekatan ini juga jauh lebih jelas daripadaif (foo && foo.bar && foo.bar.baz && foo.bar.baz.qux) { ... }
.bagaimana tentang
sumber
hasOwnProperty()
dan kali?ES6 menjawab, diuji secara menyeluruh :)
→ lihat Codepen dengan cakupan tes penuh
sumber
===
untuk falsys yang berbeda, dan menambahkan tes. Jika Anda memiliki ide yang lebih baik, beri tahu saya).false
. Dan kemudian Anda mungkin ingin memiliki nilai dalam objek Anda diatur keundefined
(Saya tahu ini aneh tetapi JS). Saya membuat nilai false positif yang ditetapkan ke'Prop not Found'
:const hasTruthyProp = prop => prop === 'Prop not found' ? false : true const path = obj => path => path.reduce((obj, prop) => { return obj && obj.hasOwnProperty(prop) ? obj[prop] : 'Prop not found' }, obj) const myFunc = compose(hasTruthyProp, path(obj))
Anda juga dapat menggunakan proposal chaining opsional tc39 bersama dengan babel 7 - tc39-proposal-opsional-chaining
Kode akan terlihat seperti ini:
sumber
Saya mencoba pendekatan rekursif:
The
! keys.length ||
tendangan dari rekursi sehingga tidak menjalankan fungsi dengan tidak ada tombol kiri untuk tes. Tes:Saya menggunakannya untuk mencetak tampilan html ramah sekelompok objek dengan kunci / nilai yang tidak diketahui, misalnya:
sumber
Saya pikir skrip berikut memberikan representasi yang lebih mudah dibaca.
mendeklarasikan suatu fungsi:
lalu gunakan seperti ini:
Saya menyebutnya "teknik badut sedih" karena menggunakan tanda o (
EDIT:
di sini adalah versi untuk TypeScript
itu memberikan pemeriksaan jenis pada waktu kompilasi (serta intellisense jika Anda menggunakan alat seperti Visual Studio)
penggunaannya sama:
tapi kali ini intellisense bekerja!
plus, Anda dapat menetapkan nilai default:
sumber
°0o <°(())))><
Object
tipe Anda . +1.buat global
function
dan gunakan di seluruh proyekcoba ini
jika kondisi
sumber
Salah satu cara sederhana adalah ini:
The
try/catch
menangkap kasus-kasus ketika salah satu tingkat yang lebih tinggi objek seperti tes, test.level1, test.level1.level2 tidak didefinisikan.sumber
Saya tidak melihat contoh seseorang menggunakan Proxy
Jadi saya membuat sendiri. Hal yang hebat tentang itu adalah Anda tidak perlu menyisipkan string. Anda benar-benar dapat mengembalikan fungsi
objek yangdapat berantai dan melakukan beberapa hal ajaib dengannya. Anda bahkan dapat memanggil fungsi dan mendapatkan indeks array untuk memeriksa objek dalamTampilkan cuplikan kode
Kode di atas berfungsi dengan baik untuk hal-hal yang sinkron. Tapi bagaimana Anda menguji sesuatu yang tidak sinkron seperti panggilan ajax ini? Bagaimana Anda mengujinya? bagaimana jika responsnya bukan json ketika mengembalikan kesalahan 500 http?
yakin Anda bisa menggunakan async / menunggu untuk menyingkirkan beberapa panggilan balik. Tetapi bagaimana jika Anda bisa melakukannya dengan lebih ajaib? sesuatu yang terlihat seperti ini:
Anda mungkin bertanya-tanya di mana semua janji &
.then
rantai ... ini bisa memblokir semua yang Anda tahu ... tetapi menggunakan teknik Proksi yang sama dengan janji, Anda benar-benar dapat menguji jalur rumit bersarang untuk keberadaannya tanpa pernah menulis fungsi tunggalTampilkan cuplikan kode
sumber
Berdasarkan jawaban ini , saya datang dengan menggunakan fungsi generik
ES2015
yang akan memecahkan masalahsumber
function validChain (object, path) { return path.split('.').reduce((a, b) => (a || { })[b], object) !== undefined }
Saya telah membuat sedikit fungsi untuk mendapatkan properti objek bersarang dengan aman.
Atau versi yang lebih sederhana namun sedikit tidak terbaca:
Atau bahkan lebih pendek tetapi tanpa fallback pada flag falsy:
Saya memiliki tes dengan:
Dan inilah beberapa tes:
Untuk melihat semua kode dengan dokumentasi dan tes yang telah saya coba, Anda dapat memeriksa github gist saya: https://gist.github.com/vsambor/3df9ad75ff3de489bbcb7b8c60beebf4#file-javascriptgetnestedvalues-js
sumber
Versi lebih pendek, versi ES5 dari jawaban istimewa CMS:
Dengan tes serupa:
sumber
checkObjHasKeys(test, ['level1', 'level2', 'asdf', 'asdf']);
success = false;
menjadireturn false
. Anda harus menyelamatkan setelah Anda tahu itu rusak, tidak ada yang lebih dalam bisa ada setelah itu nol atau tidak ditentukan. Ini akan mencegah kesalahan pada item bersarang lebih dalam, karena mereka jelas tidak ada juga.Saya pikir ini sedikit perbaikan (menjadi 1-liner):
Ini berfungsi karena operator && mengembalikan operan terakhir yang dievaluasi (dan korsleting).
sumber
Saya mencari nilai yang akan dikembalikan jika properti itu ada, jadi saya mengubah jawaban dengan CMS di atas. Inilah yang saya pikirkan:
sumber
Jawaban yang diberikan oleh CMS berfungsi dengan baik dengan modifikasi berikut untuk cek nol juga
sumber
Opsi berikut dijabarkan mulai dari jawaban ini . Pohon yang sama untuk keduanya:
Hentikan pencarian saat tidak ditentukan
Pastikan setiap level satu per satu
sumber
Saya tahu pertanyaan ini sudah lama, tetapi saya ingin menawarkan ekstensi dengan menambahkan ini ke semua objek. Saya tahu orang-orang cenderung tidak suka menggunakan prototipe Obyek untuk fungsionalitas objek yang diperluas, tetapi saya tidak menemukan sesuatu yang lebih mudah daripada melakukan ini. Plus, sekarang diizinkan dengan metode Object.defineProperty .
Sekarang, untuk menguji properti apa pun di objek apa pun yang dapat Anda lakukan:
Berikut ini adalah jsfiddle untuk mengujinya, dan khususnya mencakup beberapa jQuery yang rusak jika Anda memodifikasi Object.prototype secara langsung karena properti menjadi enumerable. Ini harus bekerja dengan baik dengan perpustakaan pihak ke-3.
sumber
Ini bekerja dengan semua objek dan array :)
ex:
ini adalah versi perbaikan dari jawaban Brian saya
Saya menggunakan _has sebagai nama properti karena dapat bertentangan dengan properti yang sudah ada (mis .: peta)
Ini biola
sumber
Inilah pendapat saya - sebagian besar solusi ini mengabaikan kasus array bersarang seperti pada:
Saya mungkin ingin memeriksa
obj.l2[0].k
Dengan fungsi di bawah ini, Anda bisa melakukannya
deeptest('l2[0].k',obj)
Fungsi akan mengembalikan true jika objek ada, false jika tidak
sumber
Sekarang kita juga dapat menggunakan
reduce
untuk mengulang melalui kunci bersarang:sumber
Anda dapat melakukan ini dengan menggunakan fungsi rekursif. Ini akan bekerja bahkan jika Anda tidak tahu semua nama kunci Object bersarang.
sumber
ada fungsi di sini diode kode (safeRead) yang akan melakukan ini dengan cara yang aman ... yaitu
jika properti apa pun adalah nol atau tidak terdefinisi, string kosong dikembalikan
sumber
Berdasarkan komentar sebelumnya , berikut adalah versi lain di mana objek utama tidak dapat didefinisikan:
sumber
Saya menulis fungsi saya sendiri yang mengambil jalur yang diinginkan, dan memiliki fungsi panggilan balik yang baik dan buruk.
Pemakaian:
sumber
sumber