Implementasi Mechanisme Warisan ECMAScript
- Halaman Sebelumnya Contoh Implementasi Mekanisme Warisan
- Halaman Berikutnya Panduan Tingkat Lanjut JavaScript
Pengimplementasian mekanisme pewarisan
Untuk melaksanakan mekanisme pewarisan dengan ECMAScript, Anda dapat memulai dari kelas dasar yang akan diwarisi. Semua kelas yang didefinisikan pengembang dapat digunakan sebagai kelas dasar. Karena alasan keamanan, kelas lokal dan kelas tuan tidak dapat digunakan sebagai kelas dasar, untuk mencegah akses publik kode yang dicompile di tingkat browser, karena kode ini dapat digunakan untuk serangan malicios.
Setelah memilih kelas dasar, Anda dapat membuat kelas turunannya. Apakah Anda menggunakan kelas dasar sepenuhnya tergantung pada keputusan Anda. Kadang-kadang, Anda mungkin ingin menciptakan kelas dasar yang tidak dapat digunakan langsung, yang hanya digunakan untuk memberikan fungsi umum bagi kelas turunan. Dalam hal ini, kelas dasar dianggap sebagai kelas abstrak.
Walaupun ECMAScript tidak mendefinisikan kelas abstrak dengan ketat seperti bahasa lain, kadang-kadang ia benar-benar menciptakan beberapa kelas yang tidak dapat digunakan. Biasanya, kelas seperti ini disebut kelas abstrak.
Kelas turunan yang dibuat akan mewarisi semua properti dan metode kelas induk, termasuk implementasi konstruktur dan metode. Ingat, semua properti dan metode adalah publik, sehingga kelas turunan dapat mengakses langsung metode ini. Kelas turunan juga dapat menambahkan properti dan metode yang belum ada di kelas induk, atau dapat menimbulkan properti dan metode kelas induk.
Cara pewarisan
Seperti fitur lainnya, cara eksekusi pewarisan ECMAScript bukan hanya satu. Ini disebabkan mekanisme pewarisan di JavaScript tidak disepakati, melainkan dieksekusi melalui imitasi. Ini berarti semua detil pewarisan bukan sepenuhnya disanggupi oleh interpreter. Sebagai pengembang, Anda memiliki hak untuk memutuskan cara pewarisan yang paling sesuai.
Di bawah ini akan disajikan beberapa cara pewarisan khusus.
Peniruan objek
Dalam merancang ECMAScript asli, tidak ada keinginan untuk merancang peniruan objek (object masquerading). Ini adalah pengembangan yang muncul saat para pengembang mulai memahami cara kerja fungsi, terutama bagaimana menggunakan keyword this dalam lingkungan fungsi.
Prinsipnya seperti berikut: constructor menggunakan keyword this untuk memberikan nilai kepada semua properti dan metode (yaitu menggunakan cara deklarasi constructor kelas). Karena constructor hanya sebuah fungsi, sehingga dapat membuat constructor ClassA menjadi method ClassB, kemudian dipanggil. ClassB akan menerima properti dan metode yang didefinisikan di constructor ClassA. Misalnya, definisi ClassA dan ClassB seperti berikut:
function ClassA(sColor) { this.color = sColor; this.sayColor = function () { alert(this.color); }; } function ClassB(sColor) { }
Ingatkan? Keyword this merujuk kepada objek yang dibuat oleh constructor saat ini. Namun dalam method ini, this menunjuk kepada objek milik method. Prinsip ini adalah menggabungkan ClassA sebagai fungsi biasa untuk membangun mekanisme pewarisan, bukannya sebagai constructor. Cara menggunakan constructor ClassB untuk mencapai mekanisme pewarisan seperti berikut:
function ClassB(sColor) { this.newMethod = ClassA; this.newMethod(sColor); delete this.newMethod; }
Pada kode ini, diberikan method newMethod untuk ClassA (ingat, nama fungsi hanya referensi ke dia). kemudian memanggil method ini, yang disampaikan adalah parameter constructor ClassB sColor. Baris kode terakhir menghapus referensi ClassA, sehingga tidak dapat dipanggil lagi nanti.
Semua properti dan metode yang baru harus didefinisikan setelah baris kode baru metode dihapus. Lainnya, mungkin akan menimpa properti dan metode yang relevan kelas induk:
function ClassB(sColor, sName) { this.newMethod = ClassA; this.newMethod(sColor); delete this.newMethod; this.name = sName; this.sayName = function () { alert(this.name); }; }
Untuk membuktikan kode sebelumnya efektif, dapat menjalankan contoh di bawah ini:
var objA = new ClassA("blue"); var objB = new ClassB("red", "John"); objA.sayColor(); // Output "blue" objB.sayColor(); // Output "red" objB.sayName(); // keluar "John"
Peniruan objek dapat mencapai pewarisan berbagai tingkatan
Yang menarik, peniruan objek dapat mendukung pewarisan berbagai tingkatan. Artinya, satu kelas dapat mewarisi beberapa kelas induk. Mechanisme pewarisan berbagai tingkatan yang dijelaskan dengan UML seperti di gambar di bawah ini:

Contoh, jika ada dua kelas ClassX dan ClassY, ClassZ ingin menggantikan keduanya, dapat digunakan kode di bawah ini:
function ClassZ() { this.newMethod = ClassX; this.newMethod(); delete this.newMethod; this.newMethod = ClassY; this.newMethod(); delete this.newMethod; }
Ada kelemahan yang ada, jika ada dua kelas ClassX dan ClassY yang memiliki properti atau metode yang sama, ClassY memiliki prioritas tinggi. Karena ia diwariskan dari kelas yang berada di belakang. Dengan demikian, kelemahan kecil ini kecuali itu, mekanisme peniru objek untuk mencapai mekanisme pengeksan berlebihan dengan mudah.
Karena kepopuleran metode ini, ECMAScript versi ketiga menambahkan dua metode ke objek Function, yaitu call() dan apply().
call() metode
call() metode sangat mirip dengan metode peniru objek klasik. Parameter pertamanya digunakan sebagai objek this. Parameter lain langsung di Passing ke fungsi itu sendiri. Contoh:
function sayColor(sPrefix,sSuffix) { alert(sPrefix + this.color + sSuffix); }; var obj = new Object(); obj.color = "blue"; sayColor.call(obj, "The color is ", "a very nice color indeed.");
Dalam contoh ini, fungsi sayColor() didefinisikan di luar objek, bahkan jika ia tidak milik objek apapun, masih dapat merujuk keyword this. Properti color objek obj sama dengan blue. Saat memanggil metode call(), parameter pertama adalah obj, yang berarti nilai keyword this di dalam fungsi sayColor() harus diisi dengan obj. Parameter kedua dan ketiga adalah string. Mereka cocok dengan parameter sPrefix dan sSuffix di dalam fungsi sayColor(). Pesan yang dihasilkan "The color is blue, a very nice color indeed." akan ditampilkan.
Untuk menggunakan metode peniru objek meleluaskan mekanisme, hanya perlu mengganti kode asosiasi, pemuatan dan penghapusan tiga baris pertama:
function ClassB(sColor, sName) { //this.newMethod = ClassA; //this.newMethod(color); //delete this.newMethod; ClassA.call(this, sColor); this.name = sName; this.sayName = function () { alert(this.name); }; }
Di sini, kami perlu membuat keyword this di ClassA sama dengan objek ClassB yang baru dibuat, jadi this adalah parameter pertama. Parameter kedua sColor unik bagi kedua kelas.
apply() metode
apply() metode memiliki dua parameter, digunakan untuk objek this dan daftar parameter yang akan di Passing ke fungsi. Contoh:
function sayColor(sPrefix,sSuffix) { alert(sPrefix + this.color + sSuffix); }; var obj = new Object(); obj.color = "blue"; sayColor.apply(obj, new Array("The color is ", "a very nice color indeed."));
Contoh ini sama seperti contoh sebelumnya, hanya saja sekarang memanggil method apply(). Ketika memanggil method apply(), parameter pertama tetap adalah obj, yang berarti hal yang harus diberikan kepada keyword this di function sayColor() adalah obj. Parameter kedua adalah array yang terdiri dari dua string, yang disesuaikan dengan parameter sPrefix dan sSuffix di function sayColor(), pesan yang dihasilkan tetap adalah "The color is blue, a very nice color indeed." dan akan ditampilkan.
Method ini juga digunakan untuk menggantikan kode asosiasi, panggilan, dan penghapusan method baru di baris pertama sampai ketiga:
function ClassB(sColor, sName) { //this.newMethod = ClassA; //this.newMethod(color); //delete this.newMethod; ClassA.apply(this, new Array(sColor)); this.name = sName; this.sayName = function () { alert(this.name); }; }
Dengan demikian, parameter pertama tetap adalah this, parameter kedua adalah array yang hanya memiliki nilai color. Dapat memasukkan seluruh object arguments ClassB sebagai parameter kedua untuk method apply():
function ClassB(sColor, sName) { //this.newMethod = ClassA; //this.newMethod(color); //delete this.newMethod; ClassA.apply(this, arguments); this.name = sName; this.sayName = function () { alert(this.name); }; }
Tentu saja, hanya parameter urutan kelas induk yang sama dengan urutan parameter kelas turunan yang mungkin untuk mengirimkan objek parameter. Jika tidak, harus dibuat array yang terpisah, menempatkan parameter dengan urutan yang benar. Selain itu, dapat digunakan method call().
Rantai prototype (prototype chaining)
Pewarisan bentuk ini aslinya digunakan untuk rantai prototype di ECMAScript. Bab sebelumnya menjelaskan cara menentukan prototype kelas. Rantai prototype ekspandir untuk mencapai mekanisme pewarisan dengan cara menarik.
Diketahui di bab sebelumnya, object prototype adalah template, dan objek yang akan diinstansiasi semua berdasarkan template ini. Secara sederhana, setiap atribut dan metode object prototype akan disampaikan ke semua instansi kelas yang sama. Prototipe rantai menggunakan fitur ini untuk mencapai mekanisme pewarisan.
Jika menggunakan cara prototype untuk menedefinikan kelas di contoh sebelumnya, mereka akan berubah menjadi bentuk berikut:
function ClassA() { } ClassA.prototype.color = "blue"; ClassA.prototype.sayColor = function () { alert(this.color); }; function ClassB() { } ClassB.prototype = new ClassA();
Peculiaritas cara prototype adalah menonjolkan baris kode biru yang dihighlight. Disini, atribut prototype ClassB diatur menjadi instansia ClassA. Ini menarik, karena ingin semua atribut dan method ClassA, tetapi tidak ingin menambahkan satu-satu ke atribut prototype ClassB. Adakah cara yang lebih baik daripada memberikan instansia ClassA ke atribut prototype?
Perhatian:Panggil konstruktur ClassA, tanpa mengirimkan parameter. Ini adalah praktek standar di prototype chain. Pastikan bahwa konstruktur tidak memiliki parameter.
Dengan mirip seperti peniruan objek, semua atribut dan method kelas turunan harus muncul setelah atribut prototype diatur, karena semua method yang diatur sebelumnya akan dihapus. Mengapa? Karena atribut prototype diganti dengan objek baru, objek asli yang menambahkan method akan dihancurkan. Jadi, kode untuk menambahkan atribut name dan method sayName() untuk kelas ClassB seperti berikut:
function ClassB() { } ClassB.prototype = new ClassA(); ClassB.prototype.name = ""; ClassB.prototype.sayName = function () { alert(this.name); };
Bisa dilakukan pengujian kode di bawah ini untuk mengecek kode ini:
var objA = new ClassA(); var objB = new ClassB(); objA.color = "blue"; objB.color = "red"; objB.name = "John"; objA.sayColor(); objB.sayColor(); objB.sayName();
Selain itu, dalam prototype chain, cara kerja operator instanceof juga sangat unik. Untuk semua instansia ClassB, instanceof untuk ClassA dan ClassB mengembalikan true. Contoh:
var objB = new ClassB(); alert(objB instanceof ClassA); // Output "true" alert(objB instanceof ClassB); // Output "true"
Dalam dunia weak typing ECMAScript, ini adalah alat yang sangat berguna, tetapi saat menggunakan peniruan objek, ini tidak dapat digunakan.
Disadvantage dari prototype chain adalah tidak mendukung multiple inheritance. Ingat, prototype chain akan menggunakan objek tipe lain untuk menulis ulang atribut prototype kelas.
Cara campuran
Cara penggantian ini menggunakan fungsi konstruktur untuk mendefinisikan kelas, bukan menggunakan prototype apapun. Masalah utama yang dihadapi saat penggunaan peniruan objek adalah perlu menggunakan cara konstruktur, ini bukan pilihan terbaik. Namun, jika menggunakan prototype chain, maka konstruktur dengan parameter tidak dapat digunakan. Bagaimana para pengembang memilih? Jawabannya sangat sederhana, kedua-duanya digunakan.
Pada bab sebelumnya, kami telah menjelaskan cara yang paling baik untuk membuat kelas adalah menggunakan konstruktor untuk mendefinisikan properti, dan menggunakan prototipe untuk mendefinisikan metode. Cara ini juga berlaku untuk mekanisme warisan, menggunakan objek untuk meniru warisan properti konstruktor, dan menggunakan prototipe untuk meniru metode objek prototype. Dengan dua cara ini, contoh sebelumnya dapat ditulis ulang seperti berikut:
function ClassA(sColor) { this.color = sColor; } ClassA.prototype.sayColor = function () { alert(this.color); }; function ClassB(sColor, sName) { ClassA.call(this, sColor); this.name = sName; } ClassB.prototype = new ClassA(); ClassB.prototype.sayName = function () { alert(this.name); };
Dalam contoh ini, mekanisme warisan disiapkan oleh dua baris kode yang disorot biru. Dalam baris kode yang disorot biru pertama, properti sColor ClassA diwarisi melalui objek di dalam konstruktor ClassB. Dalam baris kode yang disorot biru kedua, metode diwarisi melalui prototipe. Karena cara campur ini menggunakan prototipe, operator instanceof masih dapat berjalan dengan benar.
Contoh di bawah ini menguji kode ini:
var objA = new ClassA("blue"); var objB = new ClassB("red", "John"); objA.sayColor(); // Output "blue" objB.sayColor(); // Output "red" objB.sayName(); // Output "John"
- Halaman Sebelumnya Contoh Implementasi Mekanisme Warisan
- Halaman Berikutnya Panduan Tingkat Lanjut JavaScript