जावास्क्रिप्ट में शास्त्रीय विरासत बनाम प्रोटोटाइप विरासत


118

मैंने बहुत सी लिंक को गुगलाया है और शास्त्रीय विरासत और प्रोटोटाइप विरासत के बीच अंतर के बारे में अच्छा विचार प्राप्त नहीं कर सकता है?

मैंने इनमें से कुछ चीजें सीखी हैं लेकिन मैं अभी भी अवधारणाओं को लेकर उलझन में हूं।

शास्त्रीय विरासत

// 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);

क्या क्लासिकल इनहेरिटेंस अंदर प्रोटोटाइप विरासत का उपयोग करता है?

http://aaditmshah.github.io/why-prototypal-inheritance-matters/

उपरोक्त लिंक से, मैंने सीखा कि हम शास्त्रीय विरासत में रन टाइम पर नए तरीके नहीं जोड़ सकते हैं । क्या ये सही है? लेकिन आप उपरोक्त कोड की जांच कर सकते हैं मैं प्रोटोटाइप के माध्यम से "चाल" विधि और रन समय पर किसी भी तरीके को जोड़ सकता हूं । तो यह प्रोटोटाइप आधारित शास्त्रीय विरासत है? यदि ऐसा है तो वास्तविक शास्त्रीय विरासत और प्रोटोटाइप विरासत क्या है? मैं उस बारे में उलझन में हूं।

प्रोटोटाइपिक विरासत।

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);

क्या यह शास्त्रीय विरासत के समान है? मैं पूरी तरह से उलझन में हूं कि प्रोटोटाइप इनहेरिटेंस क्या है? शास्त्रीय विरासत क्या है? शास्त्रीय विरासत बुरी क्यों है?

क्या आप मुझे एक सरल तरीके से बेहतर समझ के लिए एक सरल उदाहरण दे सकते हैं।

धन्यवाद,

शिव


डुप्लिकेट, इसे देखें: stackoverflow.com/questions/1595611/…
Silviu Burcea

5
सुनिश्चित नहीं हैं कि आप यहां किस बारे में हैं - कोड का पहला ब्लॉक प्रोटोटाइपिक वंशानुक्रम है, शास्त्रीय नहीं। आपके कोड के दूसरे ब्लॉक में कोई विरासत नहीं है!
अलनीतक


@alnitak developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… यह लिंक बताता है कि एक शास्त्रीय विरासत थी। इसलिए उलझन में है।
शिवराजिनी

शास्त्रीय विरासत से बचने के लिए आप क्यों चाहते हैं, इस बारे में अधिक जानने के लिए, मेरी बात देखें, "शास्त्रीय विरासत अप्रचलित है: प्रोटोटाइप ओओ में कैसे विचार करें" vimeo.com/69255635
एरिक इलियट

जवाबों:


248

आपके प्रश्न में आपके द्वारा दिखाए गए दोनों कोड नमूने प्रोटोटाइपिक विरासत का उपयोग करते हैं। वास्तव में आप जावास्क्रिप्ट में जो भी ऑब्जेक्ट-ओरिएंटेड कोड लिखते हैं, वह प्रोटोटाइप इनहेरिटेंस का एक प्रतिमान है। जावास्क्रिप्ट केवल शास्त्रीय विरासत नहीं है। यह चीजों को थोड़ा स्पष्ट करना चाहिए:

                                   Inheritance
                                        |
                         +-----------------------------+
                         |                             |
                         v                             v
                    Prototypal                     Classical
                         |
         +------------------------------+
         |                              |
         v                              v
Prototypal Pattern             Constructor Pattern

जैसा कि आप देख सकते हैं कि प्रोटोटाइप विरासत और शास्त्रीय विरासत विरासत के दो अलग-अलग प्रतिमान हैं। सेल्फ, लुआ और जावास्क्रिप्ट जैसी कुछ भाषाएँ प्रोटोटाइप विरासत का समर्थन करती हैं। हालाँकि अधिकांश भाषाएँ जैसे C ++, Java और C # शास्त्रीय विरासत का समर्थन करती हैं।


ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग का एक त्वरित अवलोकन

दोनों प्रोटोटाइप विरासत और शास्त्रीय विरासत वस्तु उन्मुख प्रोग्रामिंग प्रतिमान हैं (यानी वे वस्तुओं से निपटते हैं)। वस्तुएं केवल अमूर्तताएं हैं जो एक वास्तविक विश्व इकाई के गुणों को कूटबद्ध करती हैं (अर्थात वे कार्यक्रम में वास्तविक शब्द चीजों का प्रतिनिधित्व करते हैं)। इसे अमूर्तन के रूप में जाना जाता है।

अमूर्तता: कंप्यूटर प्रोग्राम में वास्तविक दुनिया की चीजों का प्रतिनिधित्व।

सैद्धांतिक रूप से एक अमूर्तता को "विशिष्ट उदाहरणों से सामान्य विशेषताओं को निकालने के द्वारा गठित एक सामान्य अवधारणा" के रूप में परिभाषित किया गया है। हालांकि इस स्पष्टीकरण के लिए हम इसके बजाय उपरोक्त परिभाषा का उपयोग करने जा रहे हैं।

अब कुछ वस्तुओं में बहुत सी चीजें होती हैं। उदाहरण के लिए एक मिट्टी की बाइक और हार्ले डेविडसन में बहुत कुछ है।

एक मिट्टी बाइक:

एक मिट्टी की बाइक।

एक हार्ले डेविडसन:

ए हार्ले डेविडसन

एक मिट्टी की बाइक और एक हार्ले डेविडसन दोनों बाइक हैं। इसलिए एक बाइक एक मिट्टी की बाइक और हार्ले डेविडसन दोनों का सामान्यीकरण है।

                   Bike
                     |
    +---------------------------------+
    |                                 |
    v                                 v
Mud Bike                       Harley Davidson

उपरोक्त उदाहरण में बाइक, मिट्टी की बाइक और हार्ले डेविडसन सभी सार हैं। हालाँकि, बाइक मड बाइक और हार्ले डेविडसन (यानी कीचड़ बाइक और हार्ले डेविडसन दोनों विशिष्ट प्रकार की बाइक हैं) का अधिक सामान्य अमूर्त है।

सामान्यीकरण: एक अधिक विशिष्ट अमूर्तता का एक अमूर्तन।

ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग में हम ऑब्जेक्ट्स बनाते हैं (जो वास्तविक विश्व संस्थाओं का सार हैं) और हम इन वस्तुओं के सामान्यीकरण बनाने के लिए या तो कक्षाओं या प्रोटोटाइप का उपयोग करते हैं। सामान्यीकरण विरासत के माध्यम से बनाया जाता है। एक बाइक एक कीचड़ बाइक का सामान्यीकरण है। इसलिए कीचड़ बाइक से विरासत में मिली है।


शास्त्रीय वस्तु-उन्मुख प्रोग्रामिंग

शास्त्रीय वस्तु-उन्मुख प्रोग्रामिंग में हमारे पास दो प्रकार के सार हैं: कक्षाएं और ऑब्जेक्ट। एक वस्तु, जैसा कि पहले उल्लेख किया गया है, एक वास्तविक विश्व इकाई का अमूर्त है। दूसरी ओर एक वर्ग एक वस्तु या अन्य वर्ग का सार है (यानी यह एक सामान्यीकरण है)। उदाहरण के लिए, विचार करें:

+----------------------+----------------+---------------------------------------+
| Level of Abstraction | Name of Entity |                Comments               |
+----------------------+----------------+---------------------------------------+
| 0                    | John Doe       | Real World Entity.                    |
| 1                    | johnDoe        | Variable holding object.              |
| 2                    | Man            | Class of object johnDoe.              |
| 3                    | Human          | Superclass of class Man.              |
+----------------------+----------------+---------------------------------------+

जैसा कि आप शास्त्रीय वस्तु-उन्मुख प्रोग्रामिंग भाषाओं में देख सकते हैं कि वस्तुएं केवल अमूर्त हैं (अर्थात सभी वस्तुओं में एक एब्स्ट्रैक्शन स्तर 1 है) और कक्षाएं केवल सामान्यीकरण हैं (यानी सभी वर्गों में एब्सट्रैक्शन स्तर 1 से अधिक है)।

शास्त्रीय वस्तु-उन्मुख प्रोग्रामिंग भाषाओं में ऑब्जेक्ट केवल तात्कालिक कक्षाओं द्वारा बनाए जा सकते हैं:

class Human {
    // ...
}

class Man extends Human {
    // ...
}

Man johnDoe = new Man();

शास्त्रीय वस्तु-उन्मुख प्रोग्रामिंग भाषाओं में संक्षेप में वस्तुएं वास्तविक दुनिया की संस्थाओं का सार हैं और कक्षाएं सामान्यीकरण हैं (अर्थात या तो वस्तुओं या अन्य वर्गों का सार)।

इसलिए जैसे-जैसे अमूर्तता का स्तर बढ़ता है, वैसे-वैसे इकाइयाँ अधिक सामान्य होती जाती हैं और जैसे-जैसे अमूर्तता का स्तर घटता जाता है, वैसे-वैसे संस्थाएँ और अधिक विशिष्ट होती जाती हैं। इस अर्थ में अमूर्तता का स्तर अधिक विशिष्ट संस्थाओं से लेकर सामान्य संस्थाओं तक के पैमाने के अनुरूप है।


प्रोटोटाइप ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग

प्रोटोटाइप ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग लैंग्वेज क्लासिकल ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग लैंग्वेज की तुलना में बहुत सरल हैं क्योंकि प्रोटोटाइप ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग में हमारे पास केवल एक प्रकार का एब्सट्रैक्शन (यानी ऑब्जेक्ट्स) होता है। उदाहरण के लिए, विचार करें:

+----------------------+----------------+---------------------------------------+
| Level of Abstraction | Name of Entity |                Comments               |
+----------------------+----------------+---------------------------------------+
| 0                    | John Doe       | Real World Entity.                    |
| 1                    | johnDoe        | Variable holding object.              |
| 2                    | man            | Prototype of object johnDoe.          |
| 3                    | human          | Prototype of object man.              |
+----------------------+----------------+---------------------------------------+

जैसा कि आप प्रोटोटाइप ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग लैंग्वेज में देख सकते हैं कि ऑब्जेक्ट्स या तो वास्तविक विश्व संस्थाओं के सार हैं (जिस स्थिति में उन्हें बस ऑब्जेक्ट्स कहा जाता है) या अन्य ऑब्जेक्ट्स (जिस स्थिति में वे उन ऑब्जेक्ट्स के प्रोटोटाइप कहे जाते हैं जो वे अमूर्त होते हैं)। इसलिए एक प्रोटोटाइप एक सामान्यीकरण है।

प्रोटोटाइप ऑब्जेक्ट ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग भाषाओं में ऑब्जेक्ट्स को पूर्व-निहिलो (यानी कुछ भी नहीं) या किसी अन्य ऑब्जेक्ट से बनाया जा सकता है (जो नए बनाए गए ऑब्जेक्ट का प्रोटोटाइप बन जाता है):

var human = {};
var man = Object.create(human);
var johnDoe = Object.create(man);

मेरी विनम्र राय में प्रोटोटाइप ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग लैंग्वेज शास्त्रीय ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग भाषाओं की तुलना में अधिक शक्तिशाली हैं क्योंकि:

  1. केवल एक प्रकार का अमूर्तता है।
  2. सामान्यीकरण केवल वस्तुएं हैं।

अब तक आप शास्त्रीय विरासत और प्रोटोटाइप विरासत के बीच अंतर का एहसास कर चुके होंगे। शास्त्रीय विरासत अन्य वर्गों से विरासत में मिली कक्षाओं तक सीमित है। हालांकि प्रोटोटाइप विरासत में केवल अन्य प्रोटोटाइप से प्राप्त प्रोटोटाइप शामिल नहीं हैं, बल्कि प्रोटोटाइप से विरासत में मिली वस्तुएं भी हैं।


प्रोटोटाइप-क्लास Isomorphism

आपने देखा होगा कि प्रोटोटाइप और कक्षाएं बहुत समान हैं। यह सच है। वो हैं। वास्तव में वे इतने समान हैं कि आप वास्तव में प्रोटोटाइप का उपयोग मॉडल कक्षाओं में कर सकते हैं:

function CLASS(base, body) {
    if (arguments.length < 2) body = base, base = Object.prototype;
    var prototype = Object.create(base, {new: {value: create}});
    return body.call(prototype, base), prototype;

    function create() {
        var self = Object.create(prototype);
        return prototype.hasOwnProperty("constructor") &&
            prototype.constructor.apply(self, arguments), self;
    }
}

उपरोक्त CLASSफ़ंक्शन का उपयोग करके आप कक्षाओं की तरह दिखने वाले प्रोटोटाइप बना सकते हैं:

var Human = CLASS(function () {
    var milliseconds = 1
      , seconds      = 1000 * milliseconds
      , minutes      = 60 * seconds
      , hours        = 60 * minutes
      , days         = 24 * hours
      , years        = 365.2425 * days;

    this.constructor = function (name, sex, dob) {
        this.name = name;
        this.sex = sex;
        this.dob = dob;
    };

    this.age = function () {
        return Math.floor((new Date - this.dob) / years);
    };
});

var Man = CLASS(Human, function (Human) {
    this.constructor = function (name, dob) {
        Human.constructor.call(this, name, "male", dob);
        if (this.age() < 18) throw new Error(name + " is a boy, not a man!");
    };
});

var johnDoe = Man.new("John Doe", new Date(1970, 0, 1));

हालांकि रिवर्स सच नहीं है (यानी आप कक्षाओं को मॉडल प्रोटोटाइप का उपयोग नहीं कर सकते हैं)। इसका कारण यह है कि प्रोटोटाइप ऑब्जेक्ट हैं लेकिन क्लास ऑब्जेक्ट नहीं हैं। वे एक पूरी तरह से अलग प्रकार के अमूर्त हैं।


निष्कर्ष

संक्षेप में हमने सीखा कि एक अमूर्तता "विशिष्ट उदाहरणों से सामान्य विशेषताओं को निकालने के द्वारा बनाई गई एक सामान्य अवधारणा है" और यह सामान्यीकरण "अधिक विशिष्ट अमूर्तता का अमूर्त" है । हमने प्रोटोटाइप और शास्त्रीय विरासत के बीच अंतर के बारे में भी सीखा और कैसे दोनों एक ही सिक्के के दो चेहरे हैं।

एक बिदाई नोट पर, मैं यह कहना चाहूंगा कि प्रोटोटाइप के दो प्रकार हैं वंशानुक्रम: प्रोटोटाइप पैटर्न और निर्माण पैटर्न। प्रोटोोटाइपल पैटर्न, प्रोटोटाइपल इनहेरिटेंस का विहित पैटर्न है, जबकि कंस्ट्रक्टर पैटर्न का उपयोग प्रोटोटाइप की विरासत को शास्त्रीय विरासत की तरह देखने के लिए किया जाता है। व्यक्तिगत रूप से मैं प्रोटोटाइप पैटर्न पसंद करता हूं।

PS मैं वह व्यक्ति हूं जिसने ब्लॉग पोस्ट " Why Prototypal Inheritance Matters " लिखी है और इस सवाल का जवाब दिया " शास्त्रीय पर प्रोटोटाइप विरासत के लाभ? "। मेरा उत्तर स्वीकृत उत्तर है।


2
आपके अद्भुत जवाब के लिए धन्यवाद। मुझे यह समझने की ज़रूरत है कि कंस्ट्रक्टर पैटर्न की तुलना में प्रोटोटाइप पैटर्न बेहतर कैसे है?
शिवराजिनी

1
मैंने अपने ब्लॉग में कंस्ट्रक्टर बनाम प्रोटोटाइप के बारे में एक तुलनात्मक आलोचना लिखी है: aaditmshah.github.io/why-prototypal-inheritance-matters/…
Aadit M Shah

तो, क्या यह कहना सही होगा कि जब हम विरासत प्राप्त करने के लिए जावास्क्रिप्ट में कार्यों का उपयोग करते हैं, तो हम कुछ हद तक शास्त्रीय विरासत मॉडल का उपयोग करते हैं और जब हम सादे वस्तुओं का उपयोग करते हैं तो यह प्रोटोटाइप इनहेरिटेंस (दोनों आंतरिक रूप से प्रोटोटाइप वंशानुक्रम का पालन करते हैं)?
स्वनिधि

1
@Swanidhi No. यदि आप जावास्क्रिप्ट का उपयोग कर रहे हैं तो आप प्रोटोटाइप के उत्तराधिकार मॉडल का उपयोग कर रहे हैं। हालांकि, जावास्क्रिप्ट में प्रोटोटाइप विरासत के दो स्वाद हैं: फ़ंक्शंस (यानी कंस्ट्रक्टर पैटर्न) का उपयोग करना और ऑब्जेक्ट (यानी प्रोटोटाइप पैटर्न) का उपयोग करना।
आदित एम शाह

5
@Swanidhi No. यह अभी भी प्रोटोटाइप है। जावास्क्रिप्ट में "कक्षाएं" नहीं हैं और इसलिए निर्माणकर्ताओं सहित शास्त्रीय में जावास्क्रिप्ट में बिल्कुल कुछ भी नहीं है। यह अभी भी प्रोटोटाइप विरासत है। प्रोटोटाइपिक विरासत का सिर्फ एक अजीब रूप जो लोग शास्त्रीय विरासत के साथ भ्रमित करते हैं। संक्षेप में, , 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आशा है कि चीजों को स्पष्ट करता है।
आदित एम शाह

8

विरासत में कूदने से पहले, हम जावास्क्रिप्ट में उदाहरण (ऑब्जेक्ट्स) बनाने के लिए दो प्राथमिक मॉडल पर एक नज़र डालेंगे :

शास्त्रीय मॉडल: ऑब्जेक्ट ब्लूप्रिंट (क्लास) से बनाया गया है

class Person {
  fn() {...}
} // or constructor function say, function Person() {}

// create instance
let person = new Person();

प्रोटोटाइप मॉडल: ऑब्जेक्ट सीधे किसी अन्य ऑब्जेक्ट से बनाया जाता है।

// base object
let Person = { fn(){...} }

// instance
let person = Object.create(Person);

या तो मामले में, Inheritance * प्रोटोटाइप ऑब्जेक्ट का उपयोग करके ऑब्जेक्ट्स को लिंक करके प्राप्त किया जाता है।

(* बेस क्लास विधियां प्रोटोटाइप ऑब्जेक्ट के माध्यम से व्युत्पन्न वर्ग के माध्यम से सुलभ हैं और व्युत्पन्न वर्ग में स्पष्ट रूप से मौजूद होने की आवश्यकता नहीं है)।

बेहतर समझने के लिए यहां एक अच्छी व्याख्या दी गई है ( http://www.objectplayground.com/ )


0

कुत्ता एक जानवर है। सुजाना एक कुत्ता है। शास्त्रीय विरासत में, Animalएक वर्ग है, Dogएक उपवर्ग है Animalऔर suzannaएक उदाहरण है Dog

प्रोटोटाइप विरासत में, कोई वर्ग नहीं है। आपके पास एक है animal, जो एक वस्तु है। A dogएक अन्य ऑब्जेक्ट है, जो क्लोन करता है और विस्तारित होता है animal(प्रोटोटाइप ऑब्जेक्ट)। suzannaएक तीसरी वस्तु है, जो कॉपी और फैली हुई है dog

let animal = {hasChlorophyl: false};

let dog = Object.create(animal);
Object.assign(dog, {
  speak() {
    console.log("Woof!");
  }
});

let suzanna = Object.create(dog);
Object.assign(suzanna, {
  name: "Suzanna"
});

suzanna.speak();

यदि आप Dogइसके बजाय लिखते हैं dog, खासकर यदि आप Dogकिसी प्रकार का "कंस्ट्रक्टर" फ़ंक्शन करते हैं, तो आप प्रोटोटाइप इनहेरिटेंस नहीं कर रहे हैं; आप कर रहे हैं (छद्म-) शास्त्रीय विरासत । तथ्य यह है कि आप Object.create()इसे प्राप्त करने के लिए उपयोग कर रहे हैं इसका मतलब यह नहीं है कि आप प्रोटोटाइप इनहेरिटेंस कर रहे हैं।

वास्तव में, जावास्क्रिप्ट केवल प्रोटोटाइप विरासत का समर्थन करता है। भ्रामक newसंचालक और .prototypeविशेषता प्ररूपीय वंशानुक्रम (छद्म-) शास्त्रीय विरासत की तरह दिखने के लिए हैं।

डगलस क्रॉकफोर्ड ने अपनी पुस्तक "जावास्क्रिप्ट: द गुड पार्ट्स" में इसकी लंबाई की पड़ताल की।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.