Saya telah memprogram dengan bahasa OOP selama lebih dari 10 tahun tetapi saya belajar JavaScript sekarang dan ini pertama kalinya saya menemukan warisan berbasis prototipe. Saya cenderung belajar tercepat dengan mempelajari kode yang baik. Apa contoh aplikasi JavaScript (atau pustaka) yang ditulis dengan baik yang menggunakan pewarisan prototipe dengan benar? Dan dapatkah Anda menjelaskan (secara singkat) bagaimana / di mana warisan prototipe digunakan, jadi saya tahu harus mulai membaca dari mana?
javascript
prototypal-inheritance
Alex Reisner
sumber
sumber
Jawaban:
Douglas Crockford memiliki halaman yang bagus tentang JavaScript Prototypal Inheritance :
Base.js Dean Edward , Mootools's Class atau karya Simple Inheritance John Resig adalah cara untuk melakukan inheritance klasik dalam JavaScript.
sumber
newObj = Object.create(oldObj);
jika Anda menginginkannya tanpa kelas? Jika tidak, ganti denganoldObj
objek prototipe dari fungsi konstruktor harus bekerja?Seperti yang telah disebutkan, film-film karya Douglas Crockford memberikan penjelasan yang baik tentang mengapa dan mencakup bagaimana. Tetapi untuk memasukkannya ke dalam beberapa baris JavaScript:
// Declaring our Animal object var Animal = function () { this.name = 'unknown'; this.getName = function () { return this.name; } return this; }; // Declaring our Dog object var Dog = function () { // A private variable here var private = 42; // overriding the name this.name = "Bello"; // Implementing ".bark()" this.bark = function () { return 'MEOW'; } return this; }; // Dog extends animal Dog.prototype = new Animal(); // -- Done declaring -- // Creating an instance of Dog. var dog = new Dog(); // Proving our case console.log( "Is dog an instance of Dog? ", dog instanceof Dog, "\n", "Is dog an instance of Animal? ", dog instanceof Animal, "\n", dog.bark() +"\n", // Should be: "MEOW" dog.getName() +"\n", // Should be: "Bello" dog.private +"\n" // Should be: 'undefined' );
Masalah dengan pendekatan ini bagaimanapun, adalah bahwa itu akan membuat ulang objek setiap kali Anda membuatnya. Pendekatan lain adalah mendeklarasikan objek Anda pada tumpukan prototipe, seperti ini:
// Defining test one, prototypal var testOne = function () {}; testOne.prototype = (function () { var me = {}, privateVariable = 42; me.someMethod = function () { return privateVariable; }; me.publicVariable = "foo bar"; me.anotherMethod = function () { return this.publicVariable; }; return me; }()); // Defining test two, function var testTwo = function() { var me = {}, privateVariable = 42; me.someMethod = function () { return privateVariable; }; me.publicVariable = "foo bar"; me.anotherMethod = function () { return this.publicVariable; }; return me; }; // Proving that both techniques are functionally identical var resultTestOne = new testOne(), resultTestTwo = new testTwo(); console.log( resultTestOne.someMethod(), // Should print 42 resultTestOne.publicVariable // Should print "foo bar" ); console.log( resultTestTwo.someMethod(), // Should print 42 resultTestTwo.publicVariable // Should print "foo bar" ); // Performance benchmark start var stop, start, loopCount = 1000000; // Running testOne start = (new Date()).getTime(); for (var i = loopCount; i>0; i--) { new testOne(); } stop = (new Date()).getTime(); console.log('Test one took: '+ Math.round(((stop/1000) - (start/1000))*1000) +' milliseconds'); // Running testTwo start = (new Date()).getTime(); for (var i = loopCount; i>0; i--) { new testTwo(); } stop = (new Date()).getTime(); console.log('Test two took: '+ Math.round(((stop/1000) - (start/1000))*1000) +' milliseconds');
Ada sedikit kerugian dalam hal introspeksi. Dumping testOne, akan menghasilkan informasi yang kurang berguna. Juga properti pribadi "privateVariable" di "testOne" dibagikan di semua contoh, juga disebutkan dengan sangat membantu dalam balasan oleh shesek.
sumber
privateVariable
hanyalah variabel dalam cakupan IIFE , dan dibagikan di semua instance, jadi Anda tidak boleh menyimpan data khusus instance di dalamnya. (di testTwo itu khusus-instance, karena setiap panggilan ke testTwo () membuat cakupan baru, per-instance)Dog.prototype
. Jadi daripada menggunakanthis.bark = function () {...}
, kita bisa melakukan diDot.prototype.bark = function () {...}
luarDog
fungsi. (Lihat detail lebih lanjut dalam jawaban ini )function Shape(x, y) { this.x = x; this.y = y; } // 1. Explicitly call base (Shape) constructor from subclass (Circle) constructor passing this as the explicit receiver function Circle(x, y, r) { Shape.call(this, x, y); this.r = r; } // 2. Use Object.create to construct the subclass prototype object to avoid calling the base constructor Circle.prototype = Object.create(Shape.prototype);
sumber
Saya akan melihat di YUI , dan di
Base
perpustakaan Dean Edward : http://dean.edwards.name/weblog/2006/03/base/Untuk YUI, Anda dapat melihat sekilas modul lang , esp. yang YAHOO.lang.extend metode. Kemudian, Anda dapat menjelajahi sumber beberapa widget atau utilitas dan melihat bagaimana mereka menggunakan metode itu.
sumber
lang
setengah rusak. Adakah yang peduli untuk memperbaikinya untuk YUI 3?Ada juga pustaka ASP.NET Ajax Microsoft , http://www.asp.net/ajax/ .
Ada banyak artikel MSDN yang bagus juga, termasuk Membuat Aplikasi Web Tingkat Lanjut Dengan Teknik Berorientasi Objek .
sumber
Ini adalah contoh paling jelas yang saya temukan, dari buku Node Mixu ( http://book.mixu.net/node/ch6.html ):
sumber
ES6
class
danextends
ES6
class
danextends
hanya gula sintaks untuk kemungkinan manipulasi rantai prototipe sebelumnya, dan bisa dibilang pengaturan yang paling kanonik.Pertama pelajari lebih lanjut tentang rantai prototipe dan
.
pencarian properti di: https://stackoverflow.com/a/23877420/895245Sekarang mari kita dekonstruksi apa yang terjadi:
class C { constructor(i) { this.i = i } inc() { return this.i + 1 } } class D extends C { constructor(i) { super(i) } inc2() { return this.i + 2 } }
// Inheritance syntax works as expected. (new C(1)).inc() === 2 (new D(1)).inc() === 2 (new D(1)).inc2() === 3
// "Classes" are just function objects. C.constructor === Function C.__proto__ === Function.prototype D.constructor === Function // D is a function "indirectly" through the chain. D.__proto__ === C D.__proto__.__proto__ === Function.prototype
// "extends" sets up the prototype chain so that base class // lookups will work as expected var d = new D(1) d.__proto__ === D.prototype D.prototype.__proto__ === C.prototype // This is what `d.inc` actually does. d.__proto__.__proto__.inc === C.prototype.inc
// Class variables // No ES6 syntax sugar apparently: // /programming/22528967/es6-class-variable-alternatives C.c = 1 C.c === 1 // Because `D.__proto__ === C`. D.c === 1 // Nothing makes this work. d.c === undefined
Diagram yang disederhanakan tanpa semua objek yang telah ditentukan sebelumnya:
__proto__ (C)<---------------(D) (d) | | | | | | | | | |prototype |prototype |__proto__ | | | | | | | | | | | +---------+ | | | | | | | | | | v v |__proto__ (D.prototype) | | | | | | | | |__proto__ | | | | | | | | +--------------+ | | | | | | | v v | (C.prototype)--->(inc) | v Function.prototype
sumber
Saya sarankan melihat PrototypeJS 'Class.create:
Line 83 @ http://prototypejs.org/assets/2009/8/31/prototype.js
sumber
Contoh terbaik yang pernah saya lihat ada di JavaScript Douglas Crockford : The Good Parts . Pasti layak dibeli untuk membantu Anda mendapatkan pandangan yang seimbang tentang bahasa tersebut.
Douglas Crockford bertanggung jawab atas format JSON dan bekerja di Yahoo sebagai guru JavaScript.
sumber
Ada potongan JavaScript Prototipe berbasis Warisan dengan implementasi khusus versi ECMAScript. Ini akan secara otomatis memilih mana yang akan digunakan antara implementasi ES6, ES5 dan ES3 sesuai dengan runtime saat ini.
sumber
Menambahkan contoh pewarisan berbasis Prototipe di Javascript.
// Animal Class function Animal (name, energy) { this.name = name; this.energy = energy; } Animal.prototype.eat = function (amount) { console.log(this.name, "eating. Energy level: ", this.energy); this.energy += amount; console.log(this.name, "completed eating. Energy level: ", this.energy); } Animal.prototype.sleep = function (length) { console.log(this.name, "sleeping. Energy level: ", this.energy); this.energy -= 1; console.log(this.name, "completed sleeping. Energy level: ", this.energy); } Animal.prototype.play = function (length) { console.log(this.name, " playing. Energy level: ", this.energy); this.energy -= length; console.log(this.name, "completed playing. Energy level: ", this.energy); } // Dog Class function Dog (name, energy, breed) { Animal.call(this, name, energy); this.breed = breed; } Dog.prototype = Object.create(Animal.prototype); Dog.prototype.constructor = Dog; Dog.prototype.bark = function () { console.log(this.name, "barking. Energy level: ", this.energy); this.energy -= 1; console.log(this.name, "done barking. Energy level: ", this.energy); } Dog.prototype.showBreed = function () { console.log(this.name,"'s breed is ", this.breed); } // Cat Class function Cat (name, energy, male) { Animal.call(this, name, energy); this.male = male; } Cat.prototype = Object.create(Animal.prototype); Cat.prototype.constructor = Cat; Cat.prototype.meow = function () { console.log(this.name, "meowing. Energy level: ", this.energy); this.energy -= 1; console.log(this.name, "done meowing. Energy level: ", this.energy); } Cat.prototype.showGender = function () { if (this.male) { console.log(this.name, "is male."); } else { console.log(this.name, "is female."); } } // Instances const charlie = new Dog("Charlie", 10, "Labrador"); charlie.bark(); charlie.showBreed(); const penny = new Cat("Penny", 8, false); penny.meow(); penny.showGender();
ES6 menggunakan implementasi pewarisan yang jauh lebih mudah dengan penggunaan kata kunci konstruktor dan super.
sumber