JavaScript: menjelajahi objek

Bahan, terjemahan yang kami terbitkan hari ini, dikhususkan untuk studi objek - salah satu esensi utama dari JavaScript. Ini dirancang terutama untuk pengembang pemula yang ingin merampingkan pengetahuan mereka tentang objek.



Objek dalam JavaScript adalah koleksi dinamis properti yang, di samping itu, berisi properti "tersembunyi" yang merupakan prototipe objek. Properti objek ditandai oleh kunci dan nilai. Mari kita mulai percakapan tentang objek JS dengan kunci.

Kunci properti objek


Kunci properti objek adalah string unik. Anda dapat menggunakan dua metode untuk mengakses properti: mengaksesnya melalui suatu periode dan menentukan kunci objek dalam tanda kurung. Saat mengakses properti melalui titik, kuncinya harus berupa pengidentifikasi JavaScript yang valid. Pertimbangkan sebuah contoh:

let obj = {  message : "A message" } obj.message //"A message" obj["message"] //"A message" 

Saat mencoba mengakses properti objek yang tidak ada, pesan kesalahan tidak akan muncul, tetapi nilai yang undefined akan dikembalikan:

 obj.otherProperty //undefined 

Saat menggunakan tanda kurung siku untuk mengakses properti, Anda dapat menggunakan kunci yang bukan pengidentifikasi JavaScript yang valid (misalnya, kunci tersebut dapat berupa string yang berisi spasi). Mereka dapat memiliki nilai apa pun yang dapat dilemparkan ke string:

 let french = {}; french["merci beaucoup"] = "thank you very much"; french["merci beaucoup"]; //"thank you very much" 

Jika nilai-nilai non-string digunakan sebagai kunci, mereka secara otomatis dikonversi ke string (menggunakan, jika mungkin, metode toString() ):

 et obj = {}; //Number obj[1] = "Number 1"; obj[1] === obj["1"]; //true //Object let number1 = { toString : function() { return "1"; } } obj[number1] === obj["1"]; //true 

Dalam contoh ini, objek number1 digunakan sebagai kunci. Saat mencoba mengakses properti, properti itu dikonversi ke baris 1 , dan hasil konversi ini digunakan sebagai kunci.

Nilai Properti Obyek


Properti objek dapat berupa nilai, objek, atau fungsi primitif.

▍Object sebagai nilai properti objek


Objek dapat ditempatkan di objek lain. Pertimbangkan sebuah contoh :

 let book = { title : "The Good Parts", author : {   firstName : "Douglas",   lastName : "Crockford" } } book.author.firstName; //"Douglas" 

Pendekatan serupa dapat digunakan untuk membuat ruang nama:

 let app = {}; app.authorService = { getAuthors : function() {} }; app.bookService = { getBooks : function() {} }; 

▍ Berfungsi sebagai nilai properti objek


Ketika fungsi digunakan sebagai nilai properti objek, biasanya menjadi metode objek. Di dalam metode, untuk mengakses objek saat ini, gunakan this .

Namun kata kunci ini, mungkin memiliki arti yang berbeda, tergantung pada bagaimana fungsinya dipanggil. Di sini Anda dapat membaca tentang situasi di mana this kehilangan konteks.

Sifat dinamis dari objek


Objek dalam JavaScript, pada dasarnya, adalah entitas yang dinamis. Anda dapat menambahkan properti ke mereka kapan saja, hal yang sama berlaku untuk menghapus properti:

 let obj = {}; obj.message = "This is a message"; //   obj.otherMessage = "A new message"; //    delete obj.otherMessage; //  

Objek sebagai array asosiatif


Objek dapat dianggap sebagai array asosiatif. Kunci array asosiatif adalah nama properti objek. Untuk mengakses kunci, Anda tidak perlu melihat semua properti, yaitu operasi mengakses kunci array asosiatif berdasarkan objek dilakukan dalam O (1) waktu.

Prototipe objek


Objek memiliki tautan "tersembunyi", __proto__ , menunjuk ke objek prototipe dari mana objek mewarisi properti.

Misalnya, objek yang dibuat menggunakan objek literal memiliki tautan ke Object.prototype :

 var obj = {}; obj.__proto__ === Object.prototype; //true 

▍ Objek kosong


Seperti yang baru saja kita lihat, objek "kosong", {} , sebenarnya tidak begitu kosong, karena berisi referensi ke Object.prototype . Untuk membuat objek yang benar-benar kosong, Anda perlu menggunakan konstruksi berikut:

 Object.create(null) 

Berkat ini, sebuah objek tanpa prototipe akan dibuat. Objek seperti itu biasanya digunakan untuk membuat array asosiatif.

▍ Rantai Prototipe


Objek prototipe dapat memiliki prototipe sendiri. Jika Anda mencoba mengakses properti dari objek yang tidak ada di dalamnya, JavaScript akan mencoba menemukan properti ini dalam prototipe objek ini, dan jika properti yang diinginkan tidak ada di sana, upaya akan dilakukan untuk menemukannya di prototipe prototipe. Ini akan berlanjut sampai properti yang diinginkan ditemukan, atau sampai akhir rantai prototipe tercapai.

Nilai Jenis Primitif dan Pembungkus Objek


JavaScript memungkinkan Anda untuk bekerja dengan nilai tipe primitif sebagai objek, dalam arti bahwa bahasa tersebut memungkinkan Anda untuk mengakses properti dan metode mereka.

 (1.23).toFixed(1); //"1.2" "text".toUpperCase(); //"TEXT" true.toString(); //"true" 

Apalagi, tentu saja, nilai tipe primitif bukanlah objek.

Untuk mengatur akses ke "properti" nilai-nilai tipe primitif, JavaScript, jika perlu, membuat objek wrapper, yang, setelah mereka menjadi tidak perlu, dihancurkan. Proses membuat dan menghancurkan objek pembungkus dioptimalkan oleh mesin JS.

Pembungkus objek memiliki nilai numerik, string, dan tipe logis. Objek dari tipe yang sesuai diwakili oleh fungsi konstruktor Number , String , dan Boolean .

Prototipe Tertanam


Objek Number mewarisi properti dan metode dari prototipe Number.prototype , yang merupakan turunan dari Object.prototype :

 var no = 1; no.__proto__ === Number.prototype; //true no.__proto__.__proto__ === Object.prototype; //true 

Prototipe objek string adalah String.prototype . Prototipe objek boolean adalah Boolean.prototype . Prototipe array (yang juga objek) adalah Array.prototype .

Fungsi dalam JavaScript juga objek yang memiliki prototipe Function.prototype . Fungsi memiliki metode seperti bind() , apply() dan call() .

Semua objek, fungsi, dan objek yang mewakili nilai tipe primitif (kecuali untuk nilai null dan undefined ) mewarisi properti dan metode dari Object.prototype . Ini mengarah pada fakta bahwa, misalnya, mereka semua memiliki metode toString() .

Memperluas objek tertanam dengan polyfill


JavaScript memudahkan untuk memperluas objek yang disematkan dengan fitur baru menggunakan apa yang disebut polyfill. Polyfill adalah potongan kode yang mengimplementasikan fitur yang tidak didukung oleh browser apa pun.

▍Gunakan polyfill


Misalnya, ada polyfill untuk metode Object.assign() . Ini memungkinkan Anda untuk menambahkan fungsi baru ke Object jika tidak tersedia di dalamnya.

Hal yang sama berlaku untuk polyfill Array.from() , yang, jika metode from() tidak ada di objek Array , lengkapi dengan metode ini.

▍ Polyfill dan prototipe


Dengan bantuan polyfill, metode baru dapat ditambahkan ke prototipe objek. Misalnya, polyfill untuk String.prototype.trim() memungkinkan Anda untuk melengkapi semua objek string dengan metode trim() :

 let text = "   A text "; text.trim(); //"A text" 

Array.prototype.find() untuk Array.prototype.find() memungkinkan Anda untuk melengkapi semua array dengan metode find() . Array.prototype.findIndex() untuk Array.prototype.findIndex() bekerja dengan cara yang sama:

 let arr = ["A", "B", "C", "D", "E"]; arr.indexOf("C"); //2 

Warisan tunggal


Perintah Object.create() memungkinkan Anda membuat objek baru dengan objek prototipe yang diberikan. Perintah ini digunakan dalam JavaScript untuk menerapkan mekanisme pewarisan tunggal. Pertimbangkan sebuah contoh :

 let bookPrototype = { getFullTitle : function(){   return this.title + " by " + this.author; } } let book = Object.create(bookPrototype); book.title = "JavaScript: The Good Parts"; book.author = "Douglas Crockford"; book.getFullTitle();//JavaScript: The Good Parts by Douglas Crockford 

Warisan berganda


Perintah Object.assign() menyalin properti dari satu atau lebih objek ke objek target. Ini dapat digunakan untuk mengimplementasikan beberapa skema pewarisan. Berikut ini sebuah contoh :

 let authorDataService = { getAuthors : function() {} }; let bookDataService = { getBooks : function() {} }; let userDataService = { getUsers : function() {} }; let dataService = Object.assign({}, authorDataService, bookDataService, userDataService ); dataService.getAuthors(); dataService.getBooks(); dataService.getUsers(); 

Objek yang Tidak Berubah


Perintah Object.freeze() memungkinkan Anda untuk "membekukan" suatu objek. Anda tidak dapat menambahkan properti baru ke objek seperti itu. Properti tidak dapat dihapus, juga nilainya tidak dapat diubah. Dengan menggunakan perintah ini, suatu objek menjadi tidak berubah atau tidak berubah:

 "use strict"; let book = Object.freeze({ title : "Functional-Light JavaScript", author : "Kyle Simpson" }); book.title = "Other title";//: Cannot assign to read only property 'title' 

Perintah Object.freeze() melakukan apa yang disebut "pembekuan dangkal" objek. Ini berarti bahwa objek yang bersarang di objek "beku" dapat dimodifikasi. Untuk melakukan "pembekuan yang dalam" dari suatu objek, Anda perlu "membekukan" secara rekursif semua propertinya.

Objek Kloning


Untuk membuat klon (salinan) objek, Anda bisa menggunakan perintah Object.assign() :

 let book = Object.freeze({ title : "JavaScript Allongé", author : "Reginald Braithwaite" }); let clone = Object.assign({}, book); 

Perintah ini melakukan penyalinan objek yang dangkal, yaitu hanya menyalin properti tingkat atas. Objek bersarang ternyata umum untuk objek asli dan salinannya.

Objek literal


Literal objek memberi pengembang cara sederhana dan mudah untuk membuat objek:

 let timer = { fn : null, start : function(callback) { this.fn = callback; }, stop : function() {}, } 

Namun, metode membuat objek ini memiliki kelemahan. Secara khusus, dengan pendekatan ini, semua properti objek tersedia untuk umum, metode objek dapat didefinisikan ulang, mereka tidak dapat digunakan untuk membuat instance baru dari objek yang sama:

 timer.fn;//null timer.start = function() { console.log("New implementation"); } 

Metode Object.create ()


Dua masalah yang disebutkan di atas dapat diselesaikan melalui penggunaan bersama metode Object.create() dan Object.freeze() .

Kami menerapkan teknik ini pada contoh kami sebelumnya. Pertama, buat prototipe timerPrototype beku yang berisi semua metode yang dibutuhkan oleh berbagai instance objek. Setelah itu, buat objek yang merupakan penerus timerPrototype :

 let timerPrototype = Object.freeze({ start : function() {}, stop : function() {} }); let timer = Object.create(timerPrototype); timer.__proto__ === timerPrototype; //true 

Jika prototipe dilindungi dari perubahan, objek yang pewarisnya tidak akan dapat mengubah properti yang ditentukan dalam prototipe. Sekarang metode start() dan stop() tidak dapat diganti:

 "use strict"; timer.start = function() { console.log("New implementation"); } //: Cannot assign to read only property 'start' of object 

Object.create(timerPrototype) dapat digunakan untuk membuat beberapa objek dengan prototipe yang sama.

Fungsi konstruktor


JavaScript memiliki apa yang disebut fungsi konstruktor, yang merupakan "gula sintaksis" untuk melakukan langkah-langkah di atas untuk membuat objek baru. Pertimbangkan sebuah contoh :

 function Timer(callback){ this.fn = callback; } Timer.prototype = { start : function() {}, stop : function() {} } function getTodos() {} let timer = new Timer(getTodos); 

Anda dapat menggunakan fungsi apa pun sebagai konstruktor. Konstruktor disebut menggunakan kata kunci new . Objek yang dibuat menggunakan fungsi konstruktor bernama FunctionConstructor akan menerima prototipe FunctionConstructor.prototype :

 let timer = new Timer(); timer.__proto__ === Timer.prototype; 

Di sini, untuk mencegah perubahan prototipe, sekali lagi, Anda dapat membekukan prototipe:

 Timer.prototype = Object.freeze({ start : function() {}, stop : function() {} }); 

▍ Kata kunci baru


Ketika perintah dari bentuk new Timer() dijalankan, tindakan yang sama dilakukan ketika fungsi newTimer() melakukan di bawah ini:

 function newTimer(){ let newObj = Object.create(Timer.prototype); let returnObj = Timer.call(newObj, arguments); if(returnObj) return returnObj;   return newObj; } 

Objek baru dibuat di sini, prototipe di antaranya adalah Timer.prototype . Kemudian fungsi Timer disebut, mengatur bidang untuk objek baru.

Kata kunci kelas


ECMAScript 2015 memperkenalkan cara baru untuk melakukan tindakan di atas, yang merupakan kumpulan “gula sintaksis” lainnya. Kita berbicara tentang kata kunci class dan konstruksi terkait yang terkait dengannya. Pertimbangkan sebuah contoh :

 class Timer{ constructor(callback){   this.fn = callback; } start() {} stop() {} } Object.freeze(Timer.prototype); 

Objek yang dibuat menggunakan kata kunci class berdasarkan kelas bernama ClassName akan memiliki prototipe ClassName.prototype . Saat membuat objek berdasarkan kelas, gunakan kata kunci new :

 let timer= new Timer(); timer.__proto__ === Timer.prototype; 

Menggunakan kelas tidak membuat prototipe tidak dapat diubah. Jika perlu, mereka harus "dibekukan" dengan cara yang sama seperti yang sudah kita lakukan:

 Object.freeze(Timer.prototype); 

Warisan Berbasis Prototipe


Dalam JavaScript, objek mewarisi properti dan metode dari objek lain. Fungsi dan kelas konstruktor adalah "gula sintaksis" untuk membuat objek prototipe yang berisi semua metode yang diperlukan. Menggunakannya, objek baru dibuat yang merupakan pewaris prototipe, sifat-sifatnya, khusus untuk contoh tertentu, diatur menggunakan fungsi konstruktor atau menggunakan mekanisme kelas.

Akan lebih baik jika fungsi dan kelas konstruktor secara otomatis dapat membuat prototipe tidak berubah.

Kekuatan warisan prototipe adalah penghematan memori. Faktanya adalah bahwa prototipe dibuat hanya sekali, setelah semua objek dibuat atas dasar menggunakannya.

▍ Masalah kurangnya mekanisme enkapsulasi bawaan


Templat pewarisan prototipe tidak menggunakan pemisahan sifat-sifat objek menjadi pribadi dan publik. Semua properti objek tersedia untuk umum.

Sebagai contoh, perintah Object.keys() mengembalikan array yang berisi semua kunci properti objek. Itu dapat digunakan untuk beralih pada semua properti dari suatu objek:

 function logProperty(name){ console.log(name); //  console.log(obj[name]); //  } Object.keys(obj).forEach(logProperty); 

Ada satu pola yang meniru properti pribadi, bergantung pada kenyataan bahwa pengembang tidak akan mengakses properti yang namanya dimulai dengan garis bawah ( _ ):

 class Timer{ constructor(callback){   this._fn = callback;   this._timerId = 0; } } 

Fitur Pabrik


Objek yang dienkapsulasi dalam JavaScript dapat dibuat menggunakan fungsi pabrik. Ini terlihat seperti ini:

 function TodoStore(callback){   let fn = callback;     function start() {},   function stop() {}     return Object.freeze({      start,      stop   }); } 

Di sini variabel fn bersifat pribadi. Hanya metode start() dan stop() yang tersedia untuk umum. Metode-metode ini tidak dapat dimodifikasi secara eksternal. Kata kunci ini tidak digunakan di sini, oleh karena itu, ketika menggunakan metode ini membuat objek, masalah kehilangan konteks ini tidak relevan.

Perintah return menggunakan objek literal yang hanya berisi fungsi. Selain itu, fungsi-fungsi ini dinyatakan tertutup, mereka berbagi keadaan umum. Untuk membekukan API publik dari suatu objek, perintah Object.freeze() sudah dikenal Object.freeze() .

Di sini, dalam contoh, kami menggunakan objek Timer . Dalam materi ini Anda dapat menemukan implementasi penuhnya.

Ringkasan


Dalam JavaScript, nilai tipe primitif, objek biasa, dan fungsi diperlakukan sebagai objek. Objek memiliki sifat yang dinamis, mereka dapat digunakan sebagai array asosiatif. Objek adalah pewaris objek lain. Fungsi dan kelas konstruktor adalah "gula sintaksis", yang memungkinkan Anda membuat objek berdasarkan prototipe. Anda bisa menggunakan metode Object.create() untuk mengatur pewarisan tunggal, dan Object.create() untuk mengatur beberapa pewarisan. Anda dapat menggunakan fungsi pabrik untuk membuat objek yang dienkapsulasi.

Pembaca yang budiman! Jika Anda datang ke JavaScript dari bahasa lain, beri tahu kami apa yang Anda suka atau tidak suka tentang objek JS, dibandingkan dengan implementasi objek dalam bahasa yang sudah Anda ketahui.

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


All Articles