Detail Objek JavaScript

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-in atau dalam hasil metode Object.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) // => '101' (5    ) 

Jenis properti objek


▍ Properti Penyimpanan Data


Anda mungkin telah membuat banyak objek yang menyerupai ini:

 const obj = { name: 'Arfat', id: 5 } obj.name // => 'Arfat' 

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; // => 'Arfat' const dataObj = { name: 'Arfat', }; dataObj.name; // => 'Arfat' 

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); //        }, set id(value) {   this._id = value; } } obj.name = 'Arfat'; obj.name; // => 'ARFAT' obj.id = 5; obj.id; // => '101 

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 propertinya

Objek 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'); /* { value: 5, writable: true, enumerable: true, configurable: true } */ 

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)   // => 23 } } obj.x = 23; 

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 dari true menjadi false .
  • Sampai atribut [[Writable]] disetel ke false , atribut [[Value]] dapat diubah. Tetapi setelah atribut [[Writable]] dan [[Configurable]] disetel ke false , 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 = {}; // #1 Object.defineProperty(obj, 'id', { value: 42 }); // #2 console.log(obj); // => { } // #3 console.log(obj.id); // => 42 // #4 Object.defineProperty(obj, 'name', { value: 'Arfat', writable: false, enumerable: true, configurable: true }); // #5 console.log(obj.name); // => 'Arfat' // #6 obj.name = 'Arfat Salman' // #7 console.log(obj.name); // => 'Arfat' // (  'Arfat Salman') Object.defineProperty(obj, 'lastName', { value: 'Salman', enumerable: false, }); console.log(Object.keys(obj)); // => [ 'name' ] // #8 delete obj.id; // #9 console.log(obj.id); // => 42 //#10 Object.defineProperties(obj, { property1: {   value: 42,   writable: true }, property2: {} }); console.log(obj.property1) // => 42 

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); // => { id: 42 } 

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 ke false , 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 // ( ) obj.name = 'Arfat'; // ( ) console.log(obj); // => { id: 42 } Object.isExtensible(obj); // => false Object.isSealed(obj); //=> true 

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 // ( ) obj.name = 'Arfat'; // ( ) console.log(obj); // => { id: 42 } Object.isExtensible(obj); // => false Object.isSealed(obj); //=> true Object.isFrozen(obj); // => true 

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?

Source: https://habr.com/ru/post/id438794/


All Articles