Przeszukałem w Google tak wiele linków i nie mogę dobrze zrozumieć różnicy między dziedziczeniem klasycznym a dziedziczeniem prototypowym?
Nauczyłem się z nich kilku rzeczy, ale nadal jestem zdezorientowany.
Dziedziczenie klasyczne
// Shape - superclass
function Shape() {
this.x = 0;
this.y = 0;
}
//superclass method
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info("Shape moved.");
};
// Rectangle - subclass
function Rectangle() {
Shape.call(this); //call super constructor.
}
//subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);
Czy klasyczne dziedziczenie wykorzystuje wewnątrz dziedziczenie prototypowe?
http://aaditmshah.github.io/why-prototypal-inheritance-matters/
Z powyższego linku dowiedziałem się, że nie możemy dodawać nowych metod w czasie wykonywania w klasycznym dziedziczeniu . Czy to jest poprawne? Ale możesz sprawdzić powyższy kod , mogę dodać metodę "move" i dowolne metody w czasie wykonywania przez prototyp . Więc to jest klasyczne dziedziczenie oparte na prototypach? Jeśli tak, to jakie jest rzeczywiste dziedziczenie klasyczne i prototypowe? Jestem zdezorientowany.
Dziedziczenie prototypowe.
function Circle(radius) {
this.radius = radius;
}
Circle.prototype.area = function () {
var radius = this.radius;
return Math.PI * radius * radius;
};
Circle.prototype.circumference: function () {
return 2 * Math.PI * this.radius;
};
var circle = new Circle(5);
var circle2 = new Circle(10);
Czy jest to podobne do klasycznego dziedziczenia? Jestem całkowicie zdezorientowany, co to jest dziedziczenie prototypowe? Co to jest klasyczne dziedziczenie? Dlaczego klasyczne dziedziczenie jest złe?
Czy możesz podać prosty przykład, aby lepiej je zrozumieć w prosty sposób.
Dzięki,
Siva
źródło
Odpowiedzi:
Obie próbki kodu zademonstrowane w Twoim pytaniu wykorzystują dziedziczenie prototypowe. W rzeczywistości każdy kod zorientowany obiektowo, który piszesz w JavaScript, jest paradygmatem dziedziczenia prototypowego. JavaScript po prostu nie ma klasycznego dziedziczenia. To powinno trochę wyjaśnić:
Jak widać dziedziczenie prototypowe i klasyczne to dwa różne paradygmaty dziedziczenia. Niektóre języki, takie jak Self, Lua i JavaScript, obsługują dziedziczenie prototypowe. Jednak większość języków, takich jak C ++, Java i C #, obsługuje klasyczne dziedziczenie.
Krótki przegląd programowania obiektowego
Dziedziczenie prototypowe i klasyczne są paradygmatami programowania obiektowego (tj. Dotyczą obiektów). Obiekty są po prostu abstrakcjami, które obejmują właściwości istoty świata rzeczywistego (tj. Reprezentują rzeczywiste rzeczy słowne w programie). Nazywa się to abstrakcją.
Abstrakcja: Reprezentacja rzeczy ze świata rzeczywistego w programach komputerowych.
Teoretycznie abstrakcję definiuje się jako „ogólną koncepcję utworzoną przez wyodrębnienie wspólnych cech z konkretnych przykładów”. Jednak ze względu na to wyjaśnienie zamiast tego użyjemy powyższej definicji.
Niektóre obiekty mają teraz wiele wspólnego. Na przykład rower błotny i Harley Davidson mają ze sobą wiele wspólnego.
Rower błotny:
Harley Davidson:
Rower błotny i Harley Davidson to rowery. Stąd rower jest uogólnieniem zarówno roweru błotnego, jak i Harleya Davidsona.
W powyższym przykładzie rower, motocykl błotny i Harley Davidson są abstrakcjami. Jednak rower jest bardziej ogólną abstrakcją roweru błotnego i Harleya Davidsona (tj. Zarówno rower błotny, jak i Harley Davidson to specyficzne typy rowerów).
Uogólnienie: abstrakcja bardziej szczegółowej abstrakcji.
W programowaniu obiektowym tworzymy obiekty (które są abstrakcjami bytów ze świata rzeczywistego) i używamy klas lub prototypów do tworzenia uogólnień tych obiektów. Uogólnienia są tworzone przez dziedziczenie. Rower to uogólnienie roweru błotnego. Stąd rowery błotne dziedziczą po rowerach.
Klasyczne programowanie obiektowe
W klasycznym programowaniu obiektowym mamy dwa rodzaje abstrakcji: klasy i obiekty. Obiekt, jak wspomniano wcześniej, jest abstrakcją bytu świata rzeczywistego. Klasa z drugiej strony jest abstrakcją obiektu lub innej klasy (czyli jest uogólnieniem). Weźmy na przykład pod uwagę:
Jak widać w klasycznych zorientowanych obiektowo językach programowania obiekty są tylko abstrakcjami (tj. Wszystkie obiekty mają poziom abstrakcji 1), a klasy są tylko uogólnieniami (tj. Wszystkie klasy mają poziom abstrakcji większy niż 1).
Obiekty w klasycznych zorientowanych obiektowo językach programowania można tworzyć tylko poprzez tworzenie instancji klas:
Podsumowując, w klasycznych zorientowanych obiektowo językach programowania obiekty są abstrakcjami bytów ze świata rzeczywistego, a klasy są uogólnieniami (tj. Abstrakcjami obiektów lub innych klas).
Stąd wraz ze wzrostem poziomu abstrakcji byty stają się bardziej ogólne, a wraz ze spadkiem poziomu abstrakcji, byty stają się bardziej specyficzne. W tym sensie poziom abstrakcji jest analogiczny do skali od bytów bardziej szczegółowych do bytów bardziej ogólnych.
Prototypowe programowanie obiektowe
Prototypowe zorientowane obiektowo języki programowania są znacznie prostsze niż klasyczne zorientowane obiektowo języki programowania, ponieważ w prototypowym programowaniu zorientowanym obiektowo mamy tylko jeden typ abstrakcji (tj. Obiekty). Weźmy na przykład pod uwagę:
Jak widać w prototypowych obiektowych językach programowania, obiekty są abstrakcjami albo bytów świata rzeczywistego (w takim przypadku są po prostu nazywane obiektami), albo innych obiektów (w takim przypadku nazywane są prototypami tych obiektów, które są abstrakcyjne). Stąd prototyp jest uogólnieniem.
Obiekty w prototypowych zorientowanych obiektowo językach programowania mogą być tworzone ex-nihilo (czyli z niczego) lub z innego obiektu (który staje się prototypem nowo utworzonego obiektu):
Moim skromnym zdaniem prototypowe zorientowane obiektowo języki programowania są potężniejsze niż klasyczne zorientowane obiektowo języki programowania, ponieważ:
Do tej pory musieliście zdać sobie sprawę z różnicy między dziedziczeniem klasycznym a dziedziczeniem prototypowym. Dziedziczenie klasyczne jest ograniczone do klas dziedziczących po innych klasach. Jednak dziedziczenie prototypów obejmuje nie tylko prototypy dziedziczące po innych prototypach, ale także obiekty dziedziczące po prototypach.
Izomorfizm klasy prototypowej
Pewnie zauważyłeś, że prototypy i klasy są bardzo podobne. To prawda. Oni są. W rzeczywistości są tak podobne, że można faktycznie używać prototypów do modelowania klas:
Korzystając z powyższej
CLASS
funkcji możesz tworzyć prototypy, które wyglądają jak klasy:Jednak sytuacja odwrotna nie jest prawdą (tj. Nie można używać klas do modelowania prototypów). Dzieje się tak, ponieważ prototypy są obiektami, ale klasy nie są obiektami. To zupełnie inny rodzaj abstrakcji.
Wniosek
Podsumowując, dowiedzieliśmy się, że abstrakcja jest „ogólnym pojęciem utworzonym przez wyodrębnienie wspólnych cech z konkretnych przykładów”, a uogólnienie jest „abstrakcją bardziej szczegółowej abstrakcji” . Dowiedzieliśmy się również o różnicach między dziedziczeniem prototypowym i klasycznym oraz o tym, że oba są dwoma obliczami tej samej monety.
Na pożegnanie chciałbym zauważyć, że istnieją dwa wzorce dziedziczenia prototypowego: wzorzec prototypowy i wzorzec konstruktora. Wzorzec prototypowy to kanoniczny wzorzec dziedziczenia prototypowego, podczas gdy wzorzec konstruktora służy do nadania dziedziczeniu prototypowemu wyglądowi bardziej przypominającego dziedziczenie klasyczne. Osobiście wolę prototypowy wzór.
PS Jestem gościem, który napisał na blogu wpis „ Dlaczego dziedziczenie prototypowe ma znaczenie ” i odpowiedział na pytanie „ Korzyści z dziedziczenia prototypowego nad klasycznym? ”. Moja odpowiedź jest zaakceptowana.
źródło
programming with classes = classical inheritance
,programming with prototypes = prototypal inheritance
,programming with constructors = weird form of prototypal inheritance that looks a lot like classical inheritance
. Mam nadzieję, że to wszystko wyjaśnia.Zanim przejdziemy do dziedziczenia, przyjrzymy się dwóm podstawowym modelom do tworzenia instancji (obiektów) w javascript:
Model klasyczny: Obiekt jest tworzony z planu (klasa)
Model prototypowy: obiekt jest tworzony bezpośrednio z innego obiektu.
W obu przypadkach dziedziczenie * jest osiągane przez łączenie obiektów za pomocą obiektu prototypowego.
(* metody klasy bazowej są dostępne za pośrednictwem. klasy pochodnej poprzez obiekt prototypu i nie jest wymagane, aby były jawnie obecne w klasie pochodnej).
Oto dobre wyjaśnienie, aby lepiej zrozumieć ( http://www.objectplayground.com/ )
źródło
Pies to zwierzę. Suzanna to pies. W dziedziczeniu klasycznym
Animal
jest klasą,Dog
jest podklasąAnimal
isuzanna
jest instancją klasyDog
.W dziedziczeniu prototypowym nie ma klasy. Masz obiekt
animal
, który jest obiektem. Adog
to kolejny obiekt, który klonuje i rozszerzaanimal
(obiekt prototypowy).suzanna
to trzeci obiekt, który kopiuje i rozszerzadog
.Jeśli
Dog
zamiast tego napiszeszdog
, zwłaszcza jeśli utworzyszDog
jakąś funkcję „konstruktora”, to nie robisz dziedziczenia prototypowego; robisz (pseudo-) klasyczne dziedziczenie . Fakt, że używaszObject.create()
do tego celu, nie oznacza, że robisz dziedziczenie prototypowe.W rzeczywistości JavaScript obsługuje tylko dziedziczenie prototypowe. Mylący
new
operator i.prototype
atrybut są po to, aby dziedziczenie prototypowe wyglądało jak dziedziczenie (pseudo) klasyczne.Douglas Crockford szczegółowo bada to w swojej książce „JavaScript: The Good Parts”.
źródło