Penulis materi, terjemahan yang kami terbitkan hari ini, mengatakan bahwa objek JavaScript berisi banyak hal, keberadaannya yang bahkan tidak dapat Anda curigai, menggunakannya dalam pekerjaan sehari-hari. Objek dalam JavaScript sangat mudah dibuat, nyaman untuk digunakan, mereka tampak dapat dipahami dan fleksibel, dan banyak programmer tidak berpikir tentang fakta bahwa objek sebenarnya tidak begitu sederhana.

NB: Informasi dari publikasi dalam praktek harus diterapkan dengan sangat hati-hati dan di bawah pengawasan kolega yang lebih berpengalaman.
Di sini kita berbicara tentang apa yang tersembunyi di kedalaman objek dan mendiskusikan seluk-beluk bekerja dengan mereka.
Setelah menguasai materi ini, Anda akan tahu jawaban atas pertanyaan-pertanyaan berikut:
- Bagaimana membuat properti suatu objek tidak terhapus?
- Apa itu properti dengan metode akses dan apa saja fiturnya?
- Bagaimana membuat properti tidak berubah atau tersembunyi?
- Mengapa beberapa properti tidak terlihat di loop for-inatau dalam hasil metodeObject.keys(), dan beberapa terlihat?
- Bagaimana cara "melindungi" suatu objek dari modifikasi?
- Cara memahami sepotong kode mirip dengan yang berikut:
 obj.id = 5; console.log(obj.id)  
Jenis properti objek
▍ Properti Penyimpanan Data
Anda mungkin telah membuat banyak objek yang menyerupai ini:
 const obj = { name: 'Arfat', id: 5 } obj.name  
Properti 
name dan 
id objek 
obj disebut properti 
obj data, atau "Properti Data". Ini adalah properti yang akrab yang selalu ditemukan dalam kode JavaScript. Apa jenis properti yang dapat dimiliki objek?
▍ Properti dengan metode akses
Properti ini juga dikenal sebagai getter dan setter, mereka juga ditemukan dalam bahasa pemrograman lain seperti C # atau Python. Properti dengan Properti Accessor adalah kombinasi dari dua fungsi - 
get dan 
set .
Saat mendeklarasikan properti seperti itu, alih-alih menggunakan konstruk tipe 
: tradisional, sintaks berikut digunakan:
 const accessorObj = { get name() {   return 'Arfat'; } }; accessorObj.name;  
Lihatlah objek 
accesorObj dan bandingkan dengan objek 
dataObj . Ternyata, sekarang mereka menunjukkan perilaku yang sama. Saat menggambarkan objek pertama, kami menggunakan kata kunci 
get , diikuti oleh deklarasi fungsi. Untuk mengakses properti yang serupa, meskipun diwakili oleh suatu fungsi, Anda tidak perlu menempatkan tanda kurung setelah nama properti untuk memanggil fungsi ini. Yaitu, desain seperti 
accessorObj.name(); salah
Ketika mencoba mengakses properti 
accessorObj.name , yaitu, ketika mencoba membacanya, fungsi yang sesuai dijalankan dan nilai yang dikembalikan ke sana menjadi nilai properti 
name .
Fungsi 
get disebut getter, mereka bertanggung jawab untuk mendapatkan nilai. Jika kita melanjutkan contoh kita dan mencoba mengubah nilai properti 
name objek 
accessorObj , katakanlah, dengan menjalankan perintah 
accessorObj.name = 'New Person'; , maka ternyata tidak akan terjadi apa-apa. Intinya di sini adalah bahwa fungsi setter tidak terkait dengan kunci 
name . Fungsi tersebut memungkinkan Anda untuk menyesuaikan urutan pemberian nilai baru ke properti objek, akses yang diatur menggunakan getter.
Berikut ini deklarasi objek dengan pengambil dan penyetel:
 const accessorObj = { _name: 'Arfat', get name() {   return this._name; }, set name(value) {   this._name = value; } }; 
Fungsi setter menerima apa yang mereka coba tetapkan ke properti objek sebagai parameter. Sekarang Anda dapat menyimpan sesuatu di properti objek. Dalam hal ini, kami membuat properti "pribadi" dari objek 
_name . Karakter pertama dari nama properti semacam itu adalah garis bawah, yang tidak lebih dari sekadar petunjuk bagi pemrogram, yang menunjukkan bahwa properti ini dimaksudkan untuk kebutuhan internal objek. Lebih lanjut, kami bekerja dengannya ketika mengakses properti dari objek 
name , akses yang diatur oleh pengambil dan penyetel.
Pada saat yang sama, dalam fungsi pengambil, sebelum mengembalikan nilai properti 
_name , kita dapat memodifikasinya.
Begini tampilannya:
 const obj = { get name() {   return this._name.toUpperCase(); }, set name(value) {   this._name = value; }, get id() {   return this._id.toString(2);  
Program ini, omong-omong, berisi jawaban atas salah satu pertanyaan yang diberikan di awal artikel, yang menyangkut analisis yang tidak dapat dipahami pada kode pandangan pertama.
Mengapa seseorang membutuhkan properti dengan metode akses jika Anda dapat bekerja dengan aman dengan properti biasa? Misalnya, mereka mungkin diperlukan untuk mencatat informasi tentang pembacaan properti, atau untuk menyimpan riwayat perubahan nilai properti. Properti dengan metode akses memberi kita semua kemungkinan pemrosesan data menggunakan fungsi dan karakteristik kesederhanaan bekerja dengan properti biasa. Baca lebih lanjut tentang menggunakan properti seperti ini di 
sini .
Bagaimana JavaScript membedakan antara properti biasa yang menyimpan data dari properti dengan metode akses? Temukan ini.
Penjelas Properti Obyek
Sekilas, mungkin tampak bahwa ada korespondensi langsung antara kunci dan nilai yang disimpan dalam objek. Namun, ini tidak sepenuhnya benar.
▍ Atribut Properti
Setiap kunci objek dikaitkan dengan sekumpulan atribut yang menentukan karakteristik nilai yang terkait dengan kunci ini. Atribut ini juga dapat dianggap sebagai metadata yang menggambarkan 
: pasangan 
: .
Atribut digunakan untuk mengatur dan menggambarkan keadaan properti objek. Set atribut properti disebut deskriptor. Ada enam atribut properti:
- [[Value]]
- [[Get]]
- [[Set]]
- [[Writable]]
- [[Enumerable]]
- [[Configurable]]
Mengapa nama atribut properti dalam daftar ini terlampir dalam konstruk 
[[]] ? Tanda kurung ganda menunjukkan bahwa ini adalah entitas yang digunakan oleh mekanisme internal bahasa. Seorang programmer JS tidak dapat mengakses properti ini secara langsung. Untuk memengaruhi mereka, metode yang tepat digunakan.
Pertimbangkan gambar berikut, diambil 
dari sini , di mana Anda dapat melihat objek dan atribut propertinya.
Objek dan atribut propertinyaObjek kami memiliki 2 kunci - 
x dan 
y . Selain itu, seperangkat atribut dikaitkan dengan masing-masing atribut tersebut.
Bagaimana, menggunakan JavaScript, untuk mendapatkan informasi tentang objek, mirip dengan yang ditunjukkan pada gambar sebelumnya? Anda dapat menggunakan fungsi 
Object.getOwnPropertyDescriptor() untuk ini. Dibutuhkan objek dan nama propertinya, dan kemudian mengembalikan objek yang berisi atribut dari properti ini. Berikut ini sebuah contoh:
 const object = { x: 5, y: 6 }; Object.getOwnPropertyDescriptor(object, 'x');  
Perlu dicatat bahwa komposisi atribut dari properti tertentu tergantung pada jenisnya. Keenam atribut dari properti yang sama tidak ditemukan.
- Jika kita berbicara tentang properti dengan data, maka mereka hanya akan memiliki atribut [[Value]],[[Writable]],[[Enumerable]]dan[[Configurable]].
- Properti dengan metode akses, alih-alih atribut [[Value]]dan[[Writable]], memiliki atribut[[Get]]dan[[Set]].
▍ [[Nilai]]
Atribut ini menyimpan apa yang dikembalikan ketika mencoba untuk mendapatkan nilai properti dari suatu objek. Yaitu, jika dalam contoh sebelumnya kita menggunakan konstruksi form 
object.x , kita mendapatkan apa yang disimpan dalam atribut 
[[Value]] . Hal yang sama terjadi ketika Anda mencoba membaca properti suatu objek menggunakan tanda kurung siku.
▍ [[Get]]
Atribut ini menyimpan referensi ke suatu fungsi, yang merupakan properti pengambil. Fungsi ini dipanggil tanpa argumen ketika mencoba membaca nilai properti.
▍ [[Atur]]
Di sinilah tautan ke fungsi yang dideklarasikan saat membuat properti setter disimpan. Itu disebut dengan argumen yang mewakili nilai yang mereka coba tetapkan ke properti, yaitu, itu disebut selama setiap operasi memberikan properti nilai baru.
 const obj = { set x(val) {   console.log(val)    
Dalam contoh ini, sisi kanan ekspresi dilewatkan sebagai argumen 
val ke fungsi setter. 
Berikut adalah kode yang menunjukkan penggunaan setter dan getter.
▍ [[Tertulis]]
Atribut ini memiliki nilai boolean. Ini menunjukkan apakah nilai properti dapat ditimpa atau tidak. Jika 
false disimpan di sini, maka upaya untuk mengubah nilai properti akan gagal.
▍ [[Dihitung]]
Nilai logis juga disimpan di sini. Atribut ini mengontrol penerbitan properti 
for-in loop 
for-in . Jika disetel ke 
true , maka akan mungkin untuk bekerja dengan properti menggunakan siklus semacam itu.
▍ [[Dapat Dikonfigurasi]]
Atribut ini juga diwakili oleh nilai boolean. Inilah yang terjadi jika 
false disimpan di dalamnya:
- Properti tidak dapat dihapus.
- Anda tidak dapat mengonversi properti yang menyimpan data ke properti dengan metode akses, dan sebaliknya. Upaya untuk melakukan transformasi semacam itu tidak akan menghasilkan apa-apa.
- Itu tidak akan diizinkan untuk mengubah nilai atribut properti. Artinya, nilai atribut saat ini [[Enumerable]],[[Configurable]],[[Get]]dan[[Set]]tidak akan berubah.
Efek pengaturan atribut ini ke 
false juga tergantung pada jenis properti. Atribut ini, selain efek di atas pada properti, bekerja pada mereka dan karenanya:
- Jika ini adalah properti yang menyimpan data, maka atribut [[Writable]]hanya dapat diubah daritruemenjadifalse.
- Sampai atribut [[Writable]]disetel kefalse, atribut[[Value]]dapat diubah. Tetapi setelah atribut[[Writable]]dan[[Configurable]]disetel kefalse, properti akan berubah menjadi tidak dapat ditulis, dibatalkan, dan tidak dapat diubah.
Bekerja dengan deskriptor
Sekarang kita sudah terbiasa dengan atribut, kita akan bertanya pada diri sendiri bagaimana kita bisa memengaruhi mereka. JavaScript memiliki fungsi khusus untuk bekerja dengan deskriptor properti. Mari kita bicarakan mereka.
▍ Metode Object.getOwnPropertyDescriptor ()
Kami telah memenuhi metode ini. Itu, mengambil objek dan nama propertinya, mengembalikan entah 
undefined , atau objek dengan deskriptor properti.
▍ Metode Object.defineProperty ()
Ini adalah metode 
Object statis yang memungkinkan Anda untuk menambahkan properti ke objek atau mengubah properti yang ada. Dibutuhkan tiga argumen - objek, nama properti, dan objek dengan deskriptor. Metode ini mengembalikan objek yang dimodifikasi. Pertimbangkan sebuah contoh:
 const obj = {};  
Itu dapat dijalankan di Node.js. Kode itu ternyata cukup besar, tetapi sebenarnya cukup sederhana. Kami akan menganalisisnya, dengan fokus pada komentar dari formulir 
// #n .
Dalam fragmen 
#1 kami menggunakan fungsi 
defineProperty , meneruskannya objek 
obj , nama properti 
id , dan objek deskriptor yang hanya berisi properti 
value , menunjukkan bahwa 
42 akan ditulis ke atribut 
[[Value]] . Ingat bahwa jika Anda tidak memberikan nilai untuk atribut seperti 
[[Enumerable]] atau 
[[Configurable]] di objek ini, mereka akan disetel ke 
false secara default. Dalam hal ini, atribut 
[[Writable]] , 
[[Enumerable]] dan 
[[Configurable]] properti 
id disetel ke 
false .
Di tempat yang ditandai sebagai 
#2 , kami mencoba untuk menampilkan representasi string dari objek di konsol. Karena properti 
id -nya tidak dapat dihitung, properti itu tidak akan ditampilkan. Selain itu, properti ada, yang membuktikan keberhasilannya dengan perintah 
#3 .
Membuat objek (fragmen 
#4 ), kami mendefinisikan daftar atribut lengkap. Secara khusus, atur 
[[Writable]] ke 
false .
Dengan perintah 
#5 dan 
#7 kami menampilkan nilai properti 
name . Tetapi di antara mereka (fragmen 
#6 ) kami mencoba mengubah nilai ini. Operasi ini tidak mengubah nilai properti karena atribut 
[[Writable]] -nya disetel ke 
false . Akibatnya, kedua perintah mengeluarkan hal yang sama ke konsol.
Perintah 
#8 adalah upaya untuk menghapus properti 
id . Ingat bahwa atribut 
[[Configurable]] disetel ke 
false , yang artinya tidak dapat dihapus. Ini dibuktikan oleh tim 
#9 .
Fragmen 
#10 menunjukkan penggunaan fungsi 
Object.defineProperties () . Ia bekerja dengan cara yang sama seperti fungsi 
defineProperty() , tetapi memungkinkan, dalam satu panggilan, untuk mempengaruhi beberapa properti objek, sementara 
defineProperty() bekerja dengan hanya satu properti objek.
Perlindungan Objek
Dari waktu ke waktu, pengembang perlu melindungi objek dari gangguan luar. Misalnya, mengingat fleksibilitas JavaScript, sangat mudah untuk mengubah properti suatu objek yang seharusnya tidak berubah. Ada tiga cara utama untuk melindungi objek.
▍ Metode Object.preventExtensions ()
Metode 
Object.preventExtensions() mencegah objek dari ekspansi, yaitu menambahkan properti baru ke dalamnya. Dibutuhkan objek dan membuatnya tidak dapat diperluas. Perhatikan bahwa Anda dapat menghapus properti dari objek seperti itu. Pertimbangkan sebuah contoh:
 const obj = { id: 42 }; Object.preventExtensions(obj); obj.name = 'Arfat'; console.log(obj);  
Untuk mengetahui apakah suatu objek tidak dapat diperluas, Anda dapat menggunakan metode 
Object.isExtensible() . Jika mengembalikan 
true , maka Anda bisa menambahkan properti baru ke objek.
▍ Metode Object.seal ()
Metode 
seal() tampaknya "menyegel" objek. Inilah yang sedang kita bicarakan:
- Penggunaannya mencegah properti baru ditambahkan ke objek (dalam hal ini mirip dengan Object.preventExtensions()).
- Itu membuat semua properti objek yang ada tidak dapat dikonfigurasi.
- Nilai properti yang ada, jika atribut [[Writable]]tidak disetel kefalse, dapat diubah.
Akibatnya, ternyata metode ini mencegah penambahan properti baru ke objek dan penghapusan properti yang ada di dalamnya.
Pertimbangkan sebuah contoh:
 const obj = { id: 42 }; Object.seal(obj); delete obj.id  
Untuk memeriksa apakah objek "disegel" atau tidak, Anda dapat menggunakan metode 
Object.isSealed() .
▍ Metode Object.freeze ()
Metode 
freeze() memungkinkan Anda untuk "membekukan" objek, melengkapi mereka dengan tingkat perlindungan setinggi mungkin dalam JavaScript. Begini cara kerjanya:
- Segel objek menggunakan Object.seal().
- Benar-benar melarang modifikasi properti yang ada dari objek.
- Melarang memodifikasi deskriptor properti.
Berikut ini sebuah contoh:
 const obj = { id: 42 }; Object.freeze(obj); delete obj.id  
Anda dapat memeriksa objek apakah "beku" menggunakan metode 
Object.isFrozen() .
▍ Ikhtisar metode yang digunakan untuk melindungi objek
Penting untuk dicatat bahwa metode di atas yang digunakan untuk melindungi objek hanya memengaruhi properti mereka yang bukan objek.
Berikut ini adalah tabel ringkasan tentang metode yang dipertimbangkan untuk melindungi objek, yang diambil 
dari sini .
|  | Penciptaan Properti 
 | Membaca properti 
 | Properti menimpa 
 | Penghapusan Properti 
 | 
| Object.freeze()
 | - | + 
 | - | - | 
| Object.seal()
 | - | + 
 | + 
 | - | 
| Object.preventExtensions()
 | - | + 
 | + 
 | + 
 | 
Ringkasan
Mengingat seberapa sering objek digunakan dalam JavaScript, penting bagi setiap pengembang untuk mengetahui bagaimana mereka diatur. Kami berharap apa yang Anda pelajari dengan membaca materi ini bermanfaat bagi Anda. Selain itu, sekarang Anda tahu jawaban atas pertanyaan yang tercantum di awal artikel.
Pembaca yang budiman! Bagaimana Anda melindungi objek JavaScript?