जावास्क्रिप्ट में कई विरासत / प्रोटोटाइप


132

मैं एक ऐसे बिंदु पर आया हूं, जहां मुझे कुछ प्रकार की अल्पविकसित बहु विरासत में होने की आवश्यकता है। (मैं यहां चर्चा करने के लिए नहीं हूं कि यह एक अच्छा विचार है या नहीं, इसलिए कृपया कृपया उन टिप्पणियों को अपने पास रखें।)

मैं बस यह जानना चाहता हूं कि क्या किसी ने भी (या नहीं) सफलता के साथ ऐसा करने का प्रयास किया, और वे इसके बारे में कैसे गए।

इसे उबालने के लिए, मुझे वास्तव में जो चाहिए वह यह है कि एक वस्तु को एक से अधिक प्रोटोटाइप चेन (यानी प्रत्येक प्रोटोटाइप की अपनी उचित श्रृंखला हो सकती है) से प्राप्त करने में सक्षम एक वस्तु होने में सक्षम होना चाहिए , लेकिन पूर्ववर्ती दिए गए क्रम में (यह पहली परिभाषा के क्रम में श्रृंखला खोजें)।

यह प्रदर्शित करने के लिए कि यह सैद्धांतिक रूप से कैसे संभव है, प्राथमिक श्रृंखला के अंत में द्वितीयक श्रृंखला संलग्न करके इसे प्राप्त किया जा सकता है, लेकिन यह उन पिछले प्रोटोटाइपों में से किसी भी सभी उदाहरणों को प्रभावित करेगा और यही वह है जो मैं चाहता हूं।

विचार?


1
मुझे लगता है कि डोजो घोषित हैंडल एकाधिक वंशानुक्रम src भी मुझे लगता है mootools है भी, यह बहुत की मुझे परे है, लेकिन मैं की एक त्वरित पढ़ा है जा रहा हूँ इस डोजो के रूप में पता चलता है
TI

TraitsJS ( लिंक 1 , लिंक 2 ) पर एक नज़र डालें यह कई विरासत और मिश्रणों के लिए एक बहुत अच्छा विकल्प है ...
CMS

1
@ पॉइन्टी इसलिए क्योंकि यह बहुत गतिशील नहीं है। जैसा कि वे होते हैं, मैं या तो मूल श्रृंखला में किए गए परिवर्तनों को लेने में सक्षम होना चाहता हूं। हालाँकि उस ने कहा, अगर यह संभव नहीं है तो मुझे इसका सहारा लेना पड़ सकता है।
devios1


1
इस बारे में एक दिलचस्प पढ़ा: webreflection.blogspot.co.uk/2009/06/…
नोबिता

जवाबों:


49

प्रॉक्सी ऑब्जेक्ट्स का उपयोग करके ECMAScript 6 में एकाधिक वंशानुक्रम प्राप्त किया जा सकता है ।

कार्यान्वयन

function getDesc (obj, prop) {
  var desc = Object.getOwnPropertyDescriptor(obj, prop);
  return desc || (obj=Object.getPrototypeOf(obj) ? getDesc(obj, prop) : void 0);
}
function multiInherit (...protos) {
  return Object.create(new Proxy(Object.create(null), {
    has: (target, prop) => protos.some(obj => prop in obj),
    get (target, prop, receiver) {
      var obj = protos.find(obj => prop in obj);
      return obj ? Reflect.get(obj, prop, receiver) : void 0;
    },
    set (target, prop, value, receiver) {
      var obj = protos.find(obj => prop in obj);
      return Reflect.set(obj || Object.create(null), prop, value, receiver);
    },
    *enumerate (target) { yield* this.ownKeys(target); },
    ownKeys(target) {
      var hash = Object.create(null);
      for(var obj of protos) for(var p in obj) if(!hash[p]) hash[p] = true;
      return Object.getOwnPropertyNames(hash);
    },
    getOwnPropertyDescriptor(target, prop) {
      var obj = protos.find(obj => prop in obj);
      var desc = obj ? getDesc(obj, prop) : void 0;
      if(desc) desc.configurable = true;
      return desc;
    },
    preventExtensions: (target) => false,
    defineProperty: (target, prop, desc) => false,
  }));
}

व्याख्या

एक प्रॉक्सी ऑब्जेक्ट में एक लक्ष्य ऑब्जेक्ट और कुछ जाल होते हैं, जो मौलिक संचालन के लिए कस्टम व्यवहार को परिभाषित करते हैं।

एक वस्तु बनाते समय जो दूसरे से विरासत में मिलती है, हम उपयोग करते हैं Object.create(obj)। लेकिन इस मामले में हम कई विरासत चाहते हैं, इसलिए objमैं इसके बजाय एक प्रॉक्सी का उपयोग करता हूं जो मूलभूत कार्यों को उपयुक्त वस्तु पर पुनर्निर्देशित करेगा।

मैं इन जालों का उपयोग करता हूं:

  • hasजाल के लिए एक जाल है inऑपरेटर । मैं someयह जांचने के लिए उपयोग करता हूं कि कम से कम एक प्रोटोटाइप में संपत्ति है या नहीं।
  • getजाल संपत्ति मूल्यों प्राप्त करने के लिए एक जाल है। मैं findपहले प्रोटोटाइप को खोजने के लिए उपयोग करता हूं जिसमें वह संपत्ति होती है, और मैं मूल्य वापस करता हूं, या उपयुक्त रिसीवर पर कॉल करने वाले को बुलाता हूं। इसके द्वारा नियंत्रित किया जाता है Reflect.get। यदि किसी प्रोटोटाइप में संपत्ति नहीं है, तो मैं वापस लौट आता हूं undefined
  • setजाल संपत्ति मूल्यों की स्थापना के लिए एक जाल है। मैं findपहले प्रोटोटाइप को खोजने के लिए उपयोग करता हूं जिसमें वह संपत्ति होती है, और मैं उपयुक्त रिसीवर पर उसके सेटर को कॉल करता हूं। यदि कोई सेटर नहीं है या कोई प्रोटोटाइप में संपत्ति नहीं है, तो मूल्य उपयुक्त रिसीवर पर परिभाषित किया गया है। इसके द्वारा नियंत्रित किया जाता है Reflect.set
  • enumerateजाल के लिए एक जाल है for...inछोरों । मैं पहले प्रोटोटाइप से, फिर दूसरे से, और इसी तरह के गुणों को पुनरावृत्त करता हूं। एक बार जब कोई संपत्ति पुनरावृत्त हो जाती है, तो मैं इसे फिर से प्रसारित करने से बचने के लिए एक हैश तालिका में संग्रहीत करता हूं।
    चेतावनी : यह जाल ES7 मसौदे में हटा दिया गया है और ब्राउज़रों में पदावनत किया गया है।
  • ownKeysजाल के लिए एक जाल है Object.getOwnPropertyNames()। ES7 के बाद से, for...inलूप्स [[GetPrototypOf]] को कॉल करते रहते हैं और प्रत्येक के स्वयं के गुण प्राप्त करते रहते हैं। इसलिए सभी प्रोटोटाइप के गुणों को पुनरावृत्त करने के लिए, मैं इस जाल का उपयोग सभी समृद्ध विरासत वाले गुणों को स्वयं के गुणों की तरह बनाने के लिए करता हूं।
  • getOwnPropertyDescriptorजाल के लिए एक जाल है Object.getOwnPropertyDescriptor()। सभी प्रगणनीय गुणों को बनाना ऐसा प्रतीत होता है जैसे ownKeysजाल में स्वयं के गुण पर्याप्त नहीं हैं, for...inलूपों को यह पता लगाने के लिए कि उन्हें गणना करने योग्य है कि वे जांचने के लिए प्राप्त करेंगे। इसलिए मैं findपहले प्रोटोटाइप को खोजने के लिए उपयोग करता हूं जिसमें वह संपत्ति होती है, और जब तक मुझे संपत्ति का मालिक नहीं मिल जाता है, तब तक मैं इसकी प्रोटोटाइप श्रृंखला को पुन: व्यवस्थित करता हूं, और मैं इसके विवरणक को वापस करता हूं। यदि किसी प्रोटोटाइप में संपत्ति नहीं है, तो मैं वापस लौट आता हूं undefined। वर्णनकर्ता को इसे कॉन्फ़िगर करने योग्य बनाने के लिए संशोधित किया गया है, अन्यथा हम कुछ प्रॉक्सी आक्रमणकारियों को तोड़ सकते हैं।
  • preventExtensionsऔर definePropertyजाल केवल प्रॉक्सी लक्ष्य को संशोधित करने से इन आपरेशनों को रोकने के लिए शामिल किए गए हैं। अन्यथा हम कुछ प्रॉक्सी आक्रमणकारियों को तोड़ सकते हैं।

और भी जाल उपलब्ध हैं, जिनका मैं उपयोग नहीं करता

  • getPrototypeOfजाल जोड़ा जा सकता है, लेकिन वहाँ कई प्रोटोटाइप वापस जाने के लिए कोई उचित तरीका है। इसका तात्पर्य instanceofन तो काम नहीं करेगा। इसलिए, मैंने इसे लक्ष्य का प्रोटोटाइप प्राप्त करने दिया, जो शुरू में अशक्त है।
  • setPrototypeOfजाल जोड़ा गया है और वस्तुओं की एक सरणी स्वीकार करते हैं, जो प्रोटोटाइप की जगह लेंगे जा सकता है। इसे पाठक के लिए एक अभ्यास के रूप में छोड़ दिया जाता है। यहाँ मैं इसे लक्ष्य के प्रोटोटाइप को संशोधित करने देता हूं, जो बहुत उपयोगी नहीं है क्योंकि कोई भी जाल लक्ष्य का उपयोग नहीं करता है।
  • deletePropertyजाल स्वयं की संपत्तियों को हटाने के लिए एक जाल है। प्रॉक्सी इनहेरिटेंस का प्रतिनिधित्व करता है, इसलिए यह बहुत मायने नहीं रखेगा। मैंने इसे लक्ष्य पर हटाए जाने का प्रयास किया, जिसके पास कोई संपत्ति नहीं होनी चाहिए।
  • isExtensibleजाल तानाना प्राप्त करने के लिए एक जाल है। बहुत उपयोगी नहीं है, यह देखते हुए कि एक अपरिवर्तनीय व्यक्ति लक्ष्य के रूप में उसी विस्तार को वापस करने के लिए मजबूर करता है। इसलिए मैंने इसे ऑपरेशन को लक्ष्य पर पुनर्निर्देशित करने दिया, जो कि एक्स्टेंसिबल होगा।
  • applyऔर constructजाल बुला या instantiating के लिए जाल हैं। वे केवल तब उपयोगी होते हैं जब लक्ष्य एक फ़ंक्शन या एक निर्माता है।

उदाहरण

// Creating objects
var o1, o2, o3,
    obj = multiInherit(o1={a:1}, o2={b:2}, o3={a:3, b:3});

// Checking property existences
'a' in obj; // true   (inherited from o1)
'b' in obj; // true   (inherited from o2)
'c' in obj; // false  (not found)

// Setting properties
obj.c = 3;

// Reading properties
obj.a; // 1           (inherited from o1)
obj.b; // 2           (inherited from o2)
obj.c; // 3           (own property)
obj.d; // undefined   (not found)

// The inheritance is "live"
obj.a; // 1           (inherited from o1)
delete o1.a;
obj.a; // 3           (inherited from o3)

// Property enumeration
for(var p in obj) p; // "c", "b", "a"

1
क्या कुछ प्रदर्शन मुद्दे नहीं हैं जो सामान्य पैमाने के अनुप्रयोगों पर भी प्रासंगिक हो जाएंगे?
टॉम ज़ातो -

1
@ TomášZato यह एक सामान्य वस्तु में डेटा गुणों की तुलना में धीमा होगा, लेकिन मुझे नहीं लगता कि यह एक्सेसर गुणों की तुलना में बहुत खराब होगा।
ओरोल

टीआईएल:multiInherit(o1={a:1}, o2={b:2}, o3={a:3, b:3})
bloodKnuckles

4
मैं "मल्टीपल डेलिगेशन" के स्थान पर "मल्टीपल डेलिगेशन" के स्थान पर विचार करूंगा कि व्हाट्सएप का एक बेहतर विचार हो। आपके कार्यान्वयन में प्रमुख अवधारणा यह है कि प्रॉक्सी वास्तव में संदेश को सौंपने (या आगे) के लिए सही वस्तु का चयन कर रहा है। आपके समाधान की शक्ति यह है कि आप लक्ष्य प्रोटोटाइप को गतिशील रूप से बढ़ा सकते हैं। अन्य उत्तर समवर्ती (अला Object.assign) का उपयोग कर रहे हैं या एक बहुत अलग ग्राफ प्राप्त कर रहे हैं, अंत में उन सभी को वस्तुओं के बीच एक-एक प्रोटोटाइप श्रृंखला मिल रही है। प्रॉक्सी समाधान एक रनटाइम ब्रांचिंग प्रदान करता है, और यह चट्टानें!
sminutoli

प्रदर्शन के बारे में, यदि आप एक ऐसी वस्तु बनाते हैं जो कई वस्तुओं से विरासत में मिली है, जो कई वस्तुओं से विरासत में मिली है, और इसी तरह, तो यह और भी अधिक हो जाएगा। तो हाँ, यह धीमा होगा। लेकिन सामान्य मामलों में मुझे नहीं लगता कि यह इतना बुरा होगा।
ओरिऑल

16

अपडेट (2019): मूल पोस्ट बहुत पुरानी हो रही है। यह लेख (अब इंटरनेट आर्काइव लिंक, क्योंकि डोमेन चला गया था) और इससे जुड़ी GitHub लाइब्रेरी एक अच्छा आधुनिक दृष्टिकोण है।

मूल पद: एकाधिक वंशानुक्रम [संपादित करें, प्रकार का उचित वंशानुक्रम नहीं, बल्कि गुणों का; मिश्रण] जावास्क्रिप्ट में बहुत सीधा है अगर आप सामान्य वस्तु के बजाय निर्मित प्रोटोटाइप का उपयोग करते हैं। यहाँ से दो मूल वर्ग हैं:

function FoodPrototype() {
    this.eat = function () {
        console.log("Eating", this.name);
    };
}
function Food(name) {
    this.name = name;
}
Food.prototype = new FoodPrototype();


function PlantPrototype() {
    this.grow = function () {
        console.log("Growing", this.name);
    };
}
function Plant(name) {
    this.name = name;
}
Plant.prototype = new PlantPrototype();

ध्यान दें कि मैंने प्रत्येक मामले में उसी "नाम" सदस्य का उपयोग किया है, जो एक समस्या हो सकती है यदि माता-पिता इस बात से सहमत नहीं हैं कि "नाम" को कैसे संभाला जाए। लेकिन वे इस मामले में संगत (निरर्थक, वास्तव में) हैं।

अब हमें बस एक ऐसा वर्ग चाहिए जो दोनों से विरासत में मिले। प्रोटोटाइप प्रोटोटाइप और ऑब्जेक्ट कंस्ट्रक्टर्स के लिए कंस्ट्रक्टर फ़ंक्शन (नए कीवर्ड का उपयोग किए बिना) कॉल आईएनजी द्वारा किया जाता है । सबसे पहले, प्रोटोटाइप को मूल प्रोटोटाइप से विरासत में प्राप्त करना होगा

function FoodPlantPrototype() {
    FoodPrototype.call(this);
    PlantPrototype.call(this);
    // plus a function of its own
    this.harvest = function () {
        console.log("harvest at", this.maturity);
    };
}

और निर्माणकर्ता को मूल निर्माणकर्ताओं से विरासत में प्राप्त करना है:

function FoodPlant(name, maturity) {
    Food.call(this, name);
    Plant.call(this, name);
    // plus a property of its own
    this.maturity = maturity;
}

FoodPlant.prototype = new FoodPlantPrototype();

अब आप विभिन्न उदाहरणों को विकसित कर सकते हैं, खा सकते हैं और काट सकते हैं:

var fp1 = new FoodPlant('Radish', 28);
var fp2 = new FoodPlant('Corn', 90);

fp1.grow();
fp2.grow();
fp1.harvest();
fp1.eat();
fp2.harvest();
fp2.eat();

आप प्रोटोटाइप में निर्मित के साथ ऐसा कर सकते हैं? (ऐरे, स्ट्रिंग, संख्या)
टॉम ज़ातो -

मुझे नहीं लगता कि बिल्ट-इन प्रोटोटाइप में कंस्ट्रक्टर हैं जिन्हें आप कॉल कर सकते हैं।
रॉय जे।

ठीक है, मैं कर सकता हूँ, Array.call(...)लेकिन जो कुछ भी मैं पास करता हूँ उसे प्रभावित नहीं करता this
टॉम ज़ातो -

@ TomášZato आप कर सकते हैंArray.prototype.constructor.call()
रॉय जे।

1
@AbhishekGupta मुझे बताने के लिए धन्यवाद। मैंने लिंक को संग्रहीत वेब पेज के लिंक से बदल दिया है।
रॉय जे।

7

यह एक Object.createवास्तविक प्रोटोटाइप श्रृंखला बनाने के लिए उपयोग करता है:

function makeChain(chains) {
  var c = Object.prototype;

  while(chains.length) {
    c = Object.create(c);
    $.extend(c, chains.pop()); // some function that does mixin
  }

  return c;
}

उदाहरण के लिए:

var obj = makeChain([{a:1}, {a: 2, b: 3}, {c: 4}]);

वापस होगा:

a: 1
  a: 2
  b: 3
    c: 4
      <Object.prototype stuff>

ताकि obj.a === 1, obj.b === 3आदि


बस एक त्वरित काल्पनिक प्रश्न: मैं संख्या और ऐरे प्रोटोटाइप (मनोरंजन के लिए) को मिलाकर वेक्टर वर्ग बनाना चाहता था। यह मुझे एरे इंडेक्स और गणित ऑपरेटर दोनों देगा। लेकिन यह काम करेगा?
टॉम ज़ातो -

@ TomáZZato, अगर आप उप-वर्गीय सरणियों में देख रहे हैं, तो यह लेख देखने लायक है ; यह आपको कुछ सिरदर्द से बचा सकता है। सौभाग्य!
2332 में user3276552

5

मुझे जॉन रेजिग का एक वर्ग संरचना का कार्यान्वयन पसंद है: http://ejohn.org/blog/simple-javascript-inheritance/

यह कुछ इस तरह बढ़ाया जा सकता है:

Class.extend = function(prop /*, prop, prop, prop */) {
    for( var i=1, l=arguments.length; i<l; i++ ){
        prop = $.extend( prop, arguments[i] );
    }

    // same code
}

जो आपको विरासत में कई वस्तुओं में पारित करने की अनुमति देगा। आप instanceOfयहां क्षमता खोने जा रहे हैं, लेकिन यह एक दिया है अगर आप कई विरासत चाहते हैं।


उपर्युक्त का मेरा बल्कि जटिल उदाहरण https://github.com/cwolves/Fetch/blob/master/support/plugins/klass/klass.js पर उपलब्ध है

ध्यान दें कि उस फ़ाइल में कुछ मृत कोड है, लेकिन यदि आप एक बार देखना चाहते हैं तो यह कई विरासत की अनुमति देता है।


यदि आप जंजीर विरासत चाहते हैं (एक से अधिक विरासत नहीं, लेकिन ज्यादातर लोगों के लिए यह एक ही बात है), तो इसे कक्षा के साथ पूरा किया जा सकता है:

var newClass = Class.extend( cls1 ).extend( cls2 ).extend( cls3 )

जो मूल प्रोटोटाइप श्रृंखला को संरक्षित करेगा, लेकिन आपके पास बहुत सारे बेकार कोड होंगे।


7
यह एक विलय उथले क्लोन बनाता है। "विरासत में मिली" वस्तुओं में एक नई संपत्ति जोड़ने से व्युत्पन्न वस्तु पर नई संपत्ति दिखाई नहीं देगी, क्योंकि यह वास्तविक प्रोटोटाइप विरासत में होगा।
डैनियल इयरविकर

@DanielEarwicker - सच है, लेकिन अगर आप चाहते हैं कि "एक से अधिक विरासत" एक वर्ग दो वर्गों से प्राप्त हो, तो वास्तव में कोई विकल्प नहीं है। संशोधित उत्तर यह प्रतिबिंबित करने के लिए कि बस एक साथ कक्षाओं का पीछा करना ज्यादातर मामलों में एक ही बात है।
मार्क कहन

ऐसा लगता है कि आपका GitHUb चला गया है क्या आपके पास अभी भी github.com/cwolves/Fetch/blob/master/support/plugins/klass/ है ? यदि आप साझा करना चाहते हैं तो मैं इसे देखना नहीं चाहूंगा?
जेसनडेविस

4

एकाधिक उत्तराधिकार के जावास्क्रिप्ट फ्रेमवर्क कार्यान्वयन के साथ भ्रमित न हों।

आप सभी को निर्दिष्ट प्रोटोटाइप ऑब्जेक्ट और गुणों के साथ हर बार एक नई वस्तु बनाने के लिए Object.create () का उपयोग करने की आवश्यकता है , तो आप तुरंत पर योजना बनाते समय Object.prototyp.constructor के प्रत्येक चरण को बदलना सुनिश्चित करें।B में भविष्य।

उदाहरण के गुणों को प्राप्त करने के लिए thisAऔर thisBहम प्रत्येक ऑब्जेक्ट फ़ंक्शन के अंत में Function.prototype.call () का उपयोग करते हैं। यह वैकल्पिक है यदि आप केवल प्रोटोटाइप को इनहेरिट करने की परवाह करते हैं।

निम्नलिखित कोड को कहीं चलाएं और देखें objC:

function A() {
  this.thisA = 4; // objC will contain this property
}

A.prototype.a = 2; // objC will contain this property

B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;

function B() {
  this.thisB = 55; // objC will contain this property

  A.call(this);
}

B.prototype.b = 3; // objC will contain this property

C.prototype = Object.create(B.prototype);
C.prototype.constructor = C;

function C() {
  this.thisC = 123; // objC will contain this property

  B.call(this);
}

C.prototype.c = 2; // objC will contain this property

var objC = new C();
  • B से प्रोटोटाइप विरासत में मिला है A
  • C से प्रोटोटाइप विरासत में मिला है B
  • objC का एक उदाहरण है C

यह उपरोक्त चरणों की एक अच्छी व्याख्या है:

जावास्क्रिप्ट में ओओपी: आप क्या जानना चाहते हैं


क्या यह सभी गुणों को नए ऑब्जेक्ट में कॉपी नहीं करता है, हालांकि? इसलिए यदि आपके पास दो प्रोटोटाइप हैं, ए और बी, और आप उन दोनों को सी पर फिर से बनाते हैं, तो ए की संपत्ति को बदलने से सी और वीजा के लिए उस संपत्ति पर कोई असर नहीं पड़ेगा। आप स्मृति में संग्रहीत ए और बी में सभी गुणों की एक प्रति के साथ समाप्त करेंगे। यह उसी तरह का प्रदर्शन होगा जैसे कि आपने ए और बी के सभी गुणों को हार्ड कोड किया था। यह पठनीयता के लिए अच्छा है, और संपत्ति की खोज में माता-पिता की वस्तुओं की यात्रा नहीं है, लेकिन यह वास्तव में विरासत नहीं है - क्लोनिंग की तरह। A पर संपत्ति बदलने से क्लोन की गई संपत्ति C पर नहीं बदल जाती है
फ्रैंक

2

मैं किसी भी तरह से जावास्क्रिप्ट ओओपी पर एक विशेषज्ञ नहीं हूं, लेकिन अगर मैं आपको सही ढंग से समझता हूं कि आप कुछ चाहते हैं (छद्म कोड):

Earth.shape = 'round';
Animal.shape = 'random';

Cat inherit from (Earth, Animal);

Cat.shape = 'random' or 'round' depending on inheritance order;

उस मामले में, मैं कुछ इस तरह की कोशिश करेंगे:

var Earth = function(){};
Earth.prototype.shape = 'round';

var Animal = function(){};
Animal.prototype.shape = 'random';
Animal.prototype.head = true;

var Cat = function(){};

MultiInherit(Cat, Earth, Animal);

console.log(new Cat().shape); // yields "round", since I reversed the inheritance order
console.log(new Cat().head); // true

function MultiInherit() {
    var c = [].shift.call(arguments),
        len = arguments.length
    while(len--) {
        $.extend(c.prototype, new arguments[len]());
    }
}

1
क्या यह सिर्फ पहला प्रोटोटाइप चुनने और बाकी की अनदेखी नहीं है? c.prototypeकई बार सेट करने से कई प्रोटोटाइप नहीं मिलते हैं। उदाहरण के लिए, यदि आपके पास था Animal.isAlive = true, Cat.isAliveतब भी अपरिभाषित रहेगा।
devios1

हाँ, मैं प्रोटोटाइप को मिलाने का मतलब था, ठीक किया गया ... (मैंने यहां jQuery के विस्तार का उपयोग किया, लेकिन आपको चित्र मिलता है)
डेविड हेलिंगिंग

2

जावास्क्रिप्ट में कई विरासत को लागू करना संभव है, हालांकि बहुत कम पुस्तकालय ऐसा करते हैं।

मैं Ring.js को इंगित कर सकता हूं , एकमात्र उदाहरण जो मुझे पता है।


2

मैं आज इस पर काम कर रहा था और ईएस 6 में खुद को हासिल करने की कोशिश कर रहा था। जिस तरह से मैंने यह किया था वह Browserify, Babel का उपयोग कर रहा था और फिर मैंने इसे Wallaby के साथ परीक्षण किया और यह काम करने लगा। मेरा लक्ष्य वर्तमान एरे का विस्तार करना, ईएस 6, ईएस 7 को शामिल करना और कुछ अतिरिक्त कस्टम फीचर्स को जोड़ना है जो मुझे ऑडियो डेटा से निपटने के लिए प्रोटोटाइप में चाहिए।

Wallaby मेरे परीक्षणों में से 4 पास करता है। Example.js फ़ाइल को कंसोल में चिपकाया जा सकता है और आप देख सकते हैं कि 'शामिल' संपत्ति वर्ग के प्रोटोटाइप में है। मैं अभी भी इसे और अधिक कल का परीक्षण करना चाहता हूं।

यहाँ मेरी विधि है: (मैं कुछ नींद के बाद एक मॉड्यूल के रूप में रिफ्लेक्टर और रीपैकेज की सबसे अधिक संभावना है!)

var includes = require('./polyfills/includes');
var keys =  Object.getOwnPropertyNames(includes.prototype);
keys.shift();

class ArrayIncludesPollyfills extends Array {}

function inherit (...keys) {
  keys.map(function(key){
      ArrayIncludesPollyfills.prototype[key]= includes.prototype[key];
  });
}

inherit(keys);

module.exports = ArrayIncludesPollyfills

गितुब रेपो: https://github.com/danieldram/array-includes-polyfill


2

मुझे लगता है कि यह हास्यास्पद रूप से सरल है। यहाँ मुद्दा यह है कि बाल वर्ग केवल संदर्भित करेगाinstanceof पहली कक्षा के लिए आपको बुलाएगा

https://jsfiddle.net/1033xzyt/19/

function Foo() {
  this.bar = 'bar';
  return this;
}
Foo.prototype.test = function(){return 1;}

function Bar() {
  this.bro = 'bro';
  return this;
}
Bar.prototype.test2 = function(){return 2;}

function Cool() {
  Foo.call(this);
  Bar.call(this);

  return this;
}

var combine = Object.create(Foo.prototype);
$.extend(combine, Object.create(Bar.prototype));

Cool.prototype = Object.create(combine);
Cool.prototype.constructor = Cool;

var cool = new Cool();

console.log(cool.test()); // 1
console.log(cool.test2()); //2
console.log(cool.bro) //bro
console.log(cool.bar) //bar
console.log(cool instanceof Foo); //true
console.log(cool instanceof Bar); //false

1

नीचे दिए गए कोड की जाँच करें जिसमें IS कई उत्तराधिकार के लिए समर्थन दिखा रहा है। PROTOTYPAL INHERITANCE का उपयोग करके किया गया

function A(name) {
    this.name = name;
}
A.prototype.setName = function (name) {

    this.name = name;
}

function B(age) {
    this.age = age;
}
B.prototype.setAge = function (age) {
    this.age = age;
}

function AB(name, age) {
    A.prototype.setName.call(this, name);
    B.prototype.setAge.call(this, age);
}

AB.prototype = Object.assign({}, Object.create(A.prototype), Object.create(B.prototype));

AB.prototype.toString = function () {
    return `Name: ${this.name} has age: ${this.age}`
}

const a = new A("shivang");
const b = new B(32);
console.log(a.name);
console.log(b.age);
const ab = new AB("indu", 27);
console.log(ab.toString());

1

मेरे पास वर्गों को एकाधिक वंशानुक्रम के साथ परिभाषित करने की अनुमति देने के लिए काफी कार्य है। यह निम्नलिखित की तरह कोड के लिए अनुमति देता है। कुल मिलाकर आप जावास्क्रिप्ट में देशी क्लासिंग तकनीकों से पूर्ण प्रस्थान पर ध्यान देंगे (जैसे कि आप classकीवर्ड कभी नहीं देखेंगे ):

let human = new Running({ name: 'human', numLegs: 2 });
human.run();

let airplane = new Flying({ name: 'airplane', numWings: 2 });
airplane.fly();

let dragon = new RunningFlying({ name: 'dragon', numLegs: 4, numWings: 6 });
dragon.takeFlight();

इस तरह उत्पादन का उत्पादन करने के लिए:

human runs with 2 legs.
airplane flies away with 2 wings!
dragon runs with 4 legs.
dragon flies away with 6 wings!

यहाँ कक्षा परिभाषाएँ कैसी दिखती हैं:

let Named = makeClass('Named', {}, () => ({
  init: function({ name }) {
    this.name = name;
  }
}));

let Running = makeClass('Running', { Named }, protos => ({
  init: function({ name, numLegs }) {
    protos.Named.init.call(this, { name });
    this.numLegs = numLegs;
  },
  run: function() {
    console.log(`${this.name} runs with ${this.numLegs} legs.`);
  }
}));

let Flying = makeClass('Flying', { Named }, protos => ({
  init: function({ name, numWings }) {
    protos.Named.init.call(this, { name });
    this.numWings = numWings;
  },
  fly: function( ){
    console.log(`${this.name} flies away with ${this.numWings} wings!`);
  }
}));

let RunningFlying = makeClass('RunningFlying', { Running, Flying }, protos => ({
  init: function({ name, numLegs, numWings }) {
    protos.Running.init.call(this, { name, numLegs });
    protos.Flying.init.call(this, { name, numWings });
  },
  takeFlight: function() {
    this.run();
    this.fly();
  }
}));

हम देख सकते हैं कि makeClassफ़ंक्शन का उपयोग करने वाला प्रत्येक वर्ग परिभाषा Objectमाता-पिता-कक्षाओं के लिए मैप किए गए मूल-श्रेणी के नामों को स्वीकार करता है । यह एक फ़ंक्शन को भी स्वीकार करता है जो Objectपरिभाषित की जा रही कक्षा के लिए एक गुण देता है। इस फ़ंक्शन का एक पैरामीटर हैprotos , जिसमें किसी भी मूल-वर्ग द्वारा परिभाषित किसी भी संपत्ति तक पहुंचने के लिए पर्याप्त जानकारी है।

अंतिम टुकड़ा आवश्यक makeClassकार्य ही है, जो काफी काम करता है। यहाँ यह बाकी कोड के साथ है। मैंने makeClassकाफी भारी टिप्पणी की है:

let makeClass = (name, parents={}, propertiesFn=()=>({})) => {
  
  // The constructor just curries to a Function named "init"
  let Class = function(...args) { this.init(...args); };
  
  // This allows instances to be named properly in the terminal
  Object.defineProperty(Class, 'name', { value: name });
  
  // Tracking parents of `Class` allows for inheritance queries later
  Class.parents = parents;
  
  // Initialize prototype
  Class.prototype = Object.create(null);
  
  // Collect all parent-class prototypes. `Object.getOwnPropertyNames`
  // will get us the best results. Finally, we'll be able to reference
  // a property like "usefulMethod" of Class "ParentClass3" with:
  // `parProtos.ParentClass3.usefulMethod`
  let parProtos = {};
  for (let parName in parents) {
    let proto = parents[parName].prototype;
    parProtos[parName] = {};
    for (let k of Object.getOwnPropertyNames(proto)) {
      parProtos[parName][k] = proto[k];
    }
  }
  
  // Resolve `properties` as the result of calling `propertiesFn`. Pass
  // `parProtos`, so a child-class can access parent-class methods, and
  // pass `Class` so methods of the child-class have a reference to it
  let properties = propertiesFn(parProtos, Class);
  properties.constructor = Class; // Ensure "constructor" prop exists
  
  // If two parent-classes define a property under the same name, we
  // have a "collision". In cases of collisions, the child-class *must*
  // define a method (and within that method it can decide how to call
  // the parent-class methods of the same name). For every named
  // property of every parent-class, we'll track a `Set` containing all
  // the methods that fall under that name. Any `Set` of size greater
  // than one indicates a collision.
  let propsByName = {}; // Will map property names to `Set`s
  for (let parName in parProtos) {
    
    for (let propName in parProtos[parName]) {
      
      // Now track the property `parProtos[parName][propName]` under the
      // label of `propName`
      if (!propsByName.hasOwnProperty(propName))
        propsByName[propName] = new Set();
      propsByName[propName].add(parProtos[parName][propName]);
      
    }
    
  }
  
  // For all methods defined by the child-class, create or replace the
  // entry in `propsByName` with a Set containing a single item; the
  // child-class' property at that property name (this also guarantees
  // there is no collision at this property name). Note property names
  // prefixed with "$" will be considered class properties (and the "$"
  // will be removed).
  for (let propName in properties) {
    if (propName[0] === '$') {
      
      // The "$" indicates a class property; attach to `Class`:
      Class[propName.slice(1)] = properties[propName];
      
    } else {
      
      // No "$" indicates an instance property; attach to `propsByName`:
      propsByName[propName] = new Set([ properties[propName] ]);
      
    }
  }
  
  // Ensure that "init" is defined by a parent-class or by the child:
  if (!propsByName.hasOwnProperty('init'))
    throw Error(`Class "${name}" is missing an "init" method`);
  
  // For each property name in `propsByName`, ensure that there is no
  // collision at that property name, and if there isn't, attach it to
  // the prototype! `Object.defineProperty` can ensure that prototype
  // properties won't appear during iteration with `in` keyword:
  for (let propName in propsByName) {
    let propsAtName = propsByName[propName];
    if (propsAtName.size > 1)
      throw new Error(`Class "${name}" has conflict at "${propName}"`);
    
    Object.defineProperty(Class.prototype, propName, {
      enumerable: false,
      writable: true,
      value: propsAtName.values().next().value // Get 1st item in Set
    });
  }
  
  return Class;
};

let Named = makeClass('Named', {}, () => ({
  init: function({ name }) {
    this.name = name;
  }
}));

let Running = makeClass('Running', { Named }, protos => ({
  init: function({ name, numLegs }) {
    protos.Named.init.call(this, { name });
    this.numLegs = numLegs;
  },
  run: function() {
    console.log(`${this.name} runs with ${this.numLegs} legs.`);
  }
}));

let Flying = makeClass('Flying', { Named }, protos => ({
  init: function({ name, numWings }) {
    protos.Named.init.call(this, { name });
    this.numWings = numWings;
  },
  fly: function( ){
    console.log(`${this.name} flies away with ${this.numWings} wings!`);
  }
}));

let RunningFlying = makeClass('RunningFlying', { Running, Flying }, protos => ({
  init: function({ name, numLegs, numWings }) {
    protos.Running.init.call(this, { name, numLegs });
    protos.Flying.init.call(this, { name, numWings });
  },
  takeFlight: function() {
    this.run();
    this.fly();
  }
}));

let human = new Running({ name: 'human', numLegs: 2 });
human.run();

let airplane = new Flying({ name: 'airplane', numWings: 2 });
airplane.fly();

let dragon = new RunningFlying({ name: 'dragon', numLegs: 4, numWings: 6 });
dragon.takeFlight();

makeClassसमारोह भी वर्ग गुण का समर्थन करता है; इनको $प्रतीक के साथ संपत्ति के नामों को उपसर्ग द्वारा परिभाषित किया जाता है (ध्यान दें कि अंतिम संपत्ति का नाम जिसके परिणाम $निकाल दिए जाएंगे )। इसे ध्यान में रखते हुए, हम एक विशेष Dragonवर्ग लिख सकते हैं जो ड्रैगन के "प्रकार" को मॉडल करता है, जहां उपलब्ध ड्रैगन प्रकारों की सूची को कक्षा में ही संग्रहीत किया जाता है, उदाहरणों के विपरीत:

let Dragon = makeClass('Dragon', { RunningFlying }, protos => ({

  $types: {
    wyvern: 'wyvern',
    drake: 'drake',
    hydra: 'hydra'
  },

  init: function({ name, numLegs, numWings, type }) {
    protos.RunningFlying.init.call(this, { name, numLegs, numWings });
    this.type = type;
  },
  description: function() {
    return `A ${this.type}-type dragon with ${this.numLegs} legs and ${this.numWings} wings`;
  }
}));

let dragon1 = new Dragon({ name: 'dragon1', numLegs: 2, numWings: 4, type: Dragon.types.drake });
let dragon2 = new Dragon({ name: 'dragon2', numLegs: 4, numWings: 2, type: Dragon.types.hydra });

एकाधिक वंशानुक्रम की चुनौतियाँ

जो कोई भी कोड के लिए makeClassनिकटता से पालन ​​करता है वह चुपचाप घटित होने वाली एक महत्वपूर्ण अवांछनीय घटना को नोट करेगा जब उपरोक्त कोड चलता है: इंस्टेंट करने RunningFlyingसे परिणामकर्ता को दो कॉल आएंगे Named!

ऐसा इसलिए है क्योंकि वंशानुक्रम ग्राफ़ इस तरह दिखता है:

 (^^ More Specialized ^^)

      RunningFlying
         /     \
        /       \
    Running   Flying
         \     /
          \   /
          Named

  (vv More Abstract vv)

जब सब-क्लास 'इनहेरिटेंस ग्राफ में समान पैरेंट-क्लास के कई रास्ते होते हैं , तो सब-क्लास के इंस्टेंटिएशन कई बार उस पैरेंट-क्लास के कंस्ट्रक्टर को इन्वॉल्व करेंगे।

यह मुकाबला गैर-तुच्छ है। आइए सरलीकृत वर्गनाम के साथ कुछ उदाहरण देखें। हम वर्ग पर विचार करेंगे A, सबसे अमूर्त अभिभावक-वर्ग, वर्ग Bऔर C, जो दोनों से विरासत में मिला है A, और वर्ग BCजो विरासत में मिला है Bऔर C(और इसलिए वैचारिक रूप से "दोहरे-विरासत" A):

let A = makeClass('A', {}, () => ({
  init: function() {
    console.log('Construct A');
  }
}));
let B = makeClass('B', { A }, protos => ({
  init: function() {
    protos.A.init.call(this);
    console.log('Construct B');
  }
}));
let C = makeClass('C', { A }, protos => ({
  init: function() {
    protos.A.init.call(this);
    console.log('Construct C');
  }
}));
let BC = makeClass('BC', { B, C }, protos => ({
  init: function() {
    // Overall "Construct A" is logged twice:
    protos.B.init.call(this); // -> console.log('Construct A'); console.log('Construct B');
    protos.C.init.call(this); // -> console.log('Construct A'); console.log('Construct C');
    console.log('Construct BC');
  }
}));

यदि हम BCदोहरे आक्रमण से बचना चाहते हैं तो हमें A.prototype.initविरासत में मिले निर्माणों को सीधे कॉल करने की शैली को छोड़ना पड़ सकता है। हमें यह जांचने के लिए अप्रत्यक्ष स्तर की आवश्यकता होगी कि क्या होने से पहले डुप्लिकेट कॉल हो रही हैं, और शॉर्ट-सर्किट।

हम गुण फ़ंक्शन में दिए गए मापदंडों को बदलने पर विचार कर सकते हैं: बगल में protos, Objectजिसमें निहित गुणों का वर्णन करने वाला एक कच्चा डेटा है, हम एक उदाहरण विधि को कॉल करने के लिए एक उपयोगिता फ़ंक्शन को इस तरह से भी शामिल कर सकते हैं कि मूल तरीकों को भी कहा जाता है, लेकिन डुप्लिकेट कॉल का पता लगाया जाता है और रोका गया। आइए एक नजर डालते हैं कि हम कहां के लिए पैरामीटर स्थापित करते हैं propertiesFn Function:

let makeClass = (name, parents, propertiesFn) => {

  /* ... a bunch of makeClass logic ... */

  // Allows referencing inherited functions; e.g. `parProtos.ParentClass3.usefulMethod`
  let parProtos = {};
  /* ... collect all parent methods in `parProtos` ... */

  // Utility functions for calling inherited methods:
  let util = {};
  util.invokeNoDuplicates = (instance, fnName, args, dups=new Set()) => {

    // Invoke every parent method of name `fnName` first...
    for (let parName of parProtos) {
      if (parProtos[parName].hasOwnProperty(fnName)) {
        // Our parent named `parName` defines the function named `fnName`
        let fn = parProtos[parName][fnName];

        // Check if this function has already been encountered.
        // This solves our duplicate-invocation problem!!
        if (dups.has(fn)) continue;
        dups.add(fn);

        // This is the first time this Function has been encountered.
        // Call it on `instance`, with the desired args. Make sure we
        // include `dups`, so that if the parent method invokes further
        // inherited methods we don't lose track of what functions have
        // have already been called.
        fn.call(instance, ...args, dups);
      }
    }

  };

  // Now we can call `propertiesFn` with an additional `util` param:
  // Resolve `properties` as the result of calling `propertiesFn`:
  let properties = propertiesFn(parProtos, util, Class);

  /* ... a bunch more makeClass logic ... */

};

उपरोक्त परिवर्तन का पूरा उद्देश्य makeClassयह है कि propertiesFnजब हम आह्वान करते हैं तो हमारे पास एक अतिरिक्त तर्क होता है makeClass। हमें यह भी पता होना चाहिए कि किसी भी वर्ग में परिभाषित प्रत्येक फ़ंक्शन को अब अपने सभी अन्य, नाम के बाद एक पैरामीटर प्राप्त हो सकता है dup, जो कि एक Setऐसा कार्य है जो विरासत में मिली विधि को कॉल करने के परिणामस्वरूप सभी कार्यों को पहले से ही कहा गया है:

let A = makeClass('A', {}, () => ({
  init: function() {
    console.log('Construct A');
  }
}));
let B = makeClass('B', { A }, (protos, util) => ({
  init: function(dups) {
    util.invokeNoDuplicates(this, 'init', [ /* no args */ ], dups);
    console.log('Construct B');
  }
}));
let C = makeClass('C', { A }, (protos, util) => ({
  init: function(dups) {
    util.invokeNoDuplicates(this, 'init', [ /* no args */ ], dups);
    console.log('Construct C');
  }
}));
let BC = makeClass('BC', { B, C }, (protos, util) => ({
  init: function(dups) {
    util.invokeNoDuplicates(this, 'init', [ /* no args */ ], dups);
    console.log('Construct BC');
  }
}));

यह नई शैली वास्तव में यह सुनिश्चित करने में सफल होती है "Construct A"कि केवल एक बार लॉग इन किया जाता है जब इसका उदाहरण BCइनिशियलाइज़ किया जाता है। लेकिन तीन डाउनसाइड हैं, जिनमें से तीसरा बहुत महत्वपूर्ण है :

  1. यह कोड कम पठनीय और रखरखाव योग्य बन गया है। util.invokeNoDuplicatesफ़ंक्शन के पीछे बहुत सारी जटिलता छिप जाती है, और यह सोचकर कि यह शैली बहु-आह्वान से कैसे बचती है, गैर-सहज और सिरदर्द उत्प्रेरण है। हमारे पास वह पेसकी dupsपैरामीटर भी है , जिसे वास्तव में कक्षा में प्रत्येक एकल फ़ंक्शन पर परिभाषित करने की आवश्यकता है । आउच।
  2. यह कोड धीमा है - कई विरासतों के साथ वांछनीय परिणाम प्राप्त करने के लिए काफी अधिक अप्रत्यक्ष और संगणना आवश्यक है। दुर्भाग्य से यह हमारी बहु-मंगलाचरण समस्या के किसी भी समाधान के साथ होने की संभावना है।
  3. सबसे महत्वपूर्ण बात, कार्यों की संरचना जो विरासत पर निर्भर करती है, बहुत कठोर हो गई है । यदि कोई उप-वर्ग NiftyClassकिसी फ़ंक्शन को ओवरराइड करता है niftyFunction, और util.invokeNoDuplicates(this, 'niftyFunction', ...)इसे डुप्लिकेट-इनवोकेशन के बिना चलाने के लिए उपयोग करता है, तो इसे परिभाषित करने वाले प्रत्येक माता-पिता वर्ग NiftyClass.prototype.niftyFunctionके फ़ंक्शन को कॉल करेगा , niftyFunctionउन कक्षाओं से किसी भी रिटर्न मान को अनदेखा करेगा, और अंत में विशेष तर्क का प्रदर्शन करेगा NiftyClass.prototype.niftyFunction। यह एकमात्र संभव संरचना है । यदि NiftyClassविरासत CoolClassऔर GoodClass, और ये दोनों मूल-वर्ग niftyFunctionअपनी स्वयं की परिभाषा प्रदान करते हैं, NiftyClass.prototype.niftyFunctionतो कभी भी (एकाधिक-आह्वान के जोखिम के बिना) नहीं कर पाएंगे:
    • NiftyClass पहले के विशेष तर्क को चलाते हैं , फिर अभिभावक-वर्गों के विशेष तर्क को
    • B. सभी विशेष अभिभावक तर्क पूर्ण होने के बादNiftyClass किसी भी बिंदु पर विशेष तर्क को चलाएं
    • C. अपने माता-पिता के विशेष तर्क के वापसी मूल्यों के आधार पर सशर्त व्यवहार करें
    • डी से बचें एक विशेष माता-पिता चल विशेष है niftyFunctionपूरी तरह

निश्चित रूप से, हम विशेष प्रकार के कार्यों को परिभाषित करके उपरोक्त प्रत्येक अक्षरित समस्या को हल कर सकते हैं util:

  • परिभाषित करते हैंutil.invokeNoDuplicatesSubClassLogicFirst(instance, fnName, ...)
  • बी डिफाइन util.invokeNoDuplicatesSubClassAfterParent(parentName, instance, fnName, ...)( parentNameउस अभिभावक का नाम कहां है जिसका विशेष तर्क बच्चे के वर्ग विशेष के तर्क के तुरंत बाद होगा)
  • C. परिभाषित util.invokeNoDuplicatesCanShortCircuitOnParent(parentName, testFn, instance, fnName, ...)(इस मामले में testFnनामांकित माता-पिता के लिए विशेष तर्क का परिणाम प्राप्त होगा parentName, और यह true/falseदर्शाता है कि शॉर्ट-सर्किट होगा या नहीं यह मान लौटाएगा )
  • डी। डिफाइन util.invokeNoDuplicatesBlackListedParents(blackList, instance, fnName, ...)(इस मामले में blackListउन Arrayअभिभावकों के नाम होंगे जिनके विशेष तर्क को पूरी तरह छोड़ दिया जाना चाहिए)

ये समाधान सभी उपलब्ध हैं, लेकिन यह कुल तबाही है ! प्रत्येक अद्वितीय संरचना के लिए जो विरासत में मिली फ़ंक्शन कॉल ले सकती है, हमें इसके तहत परिभाषित एक विशेष विधि की आवश्यकता होगी util। क्या एक पूर्ण आपदा।

इसे ध्यान में रखते हुए हम अच्छी बहु विरासत को लागू करने की चुनौतियों को देखना शुरू कर सकते हैं। makeClassइस उत्तर में मैंने जो पूर्ण कार्यान्वयन प्रदान किया है, वह बहु-इनवोकेशन समस्या, या कई अन्य समस्याओं पर विचार नहीं करता है जो कई उत्तराधिकार के संबंध में उत्पन्न होती हैं।

यह उत्तर बहुत लंबा हो रहा है। मुझे आशा है कि मैंने जो makeClassकार्यान्वयन शामिल किया है वह अभी भी उपयोगी है, भले ही यह सही न हो। मुझे आशा है कि इस विषय में रुचि रखने वाले किसी भी व्यक्ति ने आगे पढ़ने के लिए ध्यान रखने के लिए अधिक संदर्भ प्राप्त किया है!


0

पैकेज IeUnit पर एक नज़र डालें

IeUnit में लागू की गई अवधारणा आत्मसात करने से लगता है कि आप काफी गतिशील तरीके से क्या देख रहे हैं।


0

निर्माण कार्यों का उपयोग करते हुए प्रोटोटाइप का एक उदाहरण यहां दिया गया है :

function Lifeform () {             // 1st Constructor function
    this.isLifeform = true;
}

function Animal () {               // 2nd Constructor function
    this.isAnimal = true;
}
Animal.prototype = new Lifeform(); // Animal is a lifeform

function Mammal () {               // 3rd Constructor function
    this.isMammal = true;
}
Mammal.prototype = new Animal();   // Mammal is an animal

function Cat (species) {           // 4th Constructor function
    this.isCat = true;
    this.species = species
}
Cat.prototype = new Mammal();     // Cat is a mammal

इस अवधारणा में जावास्क्रिप्ट के लिए "क्लास" की परिभाषा में येहुदा काट्ज़ का उपयोग किया गया है :

... एक जावास्क्रिप्ट "क्लास" सिर्फ एक फंक्शन ऑब्जेक्ट है जो एक कंस्ट्रक्टर प्लस एक संलग्न प्रोटोटाइप ऑब्जेक्ट के रूप में कार्य करता है। ( स्रोत: गुरु काट्ज )

Object.create दृष्टिकोण के विपरीत , जब कक्षाएं इस तरह से बनाई जाती हैं और हम एक "वर्ग" के उदाहरण बनाना चाहते हैं, तो हमें यह जानने की आवश्यकता नहीं है कि प्रत्येक "वर्ग" किस से विरासत में मिला है। हम सिर्फ उपयोग करते हैं new

// Make an instance object of the Cat "Class"
var tiger = new Cat("tiger");

console.log(tiger.isCat, tiger.isMammal, tiger.isAnimal, tiger.isLifeform);
// Outputs: true true true true

प्राथमिकता के क्रम को समझ में आना चाहिए। पहले यह उदाहरण ऑब्जेक्ट में दिखता है, फिर यह प्रोटोटाइप है, फिर अगला प्रोटोटाइप आदि।

// Let's say we have another instance, a special alien cat
var alienCat = new Cat("alien");
// We can define a property for the instance object and that will take 
// precendence over the value in the Mammal class (down the chain)
alienCat.isMammal = false;
// OR maybe all cats are mutated to be non-mammals
Cat.prototype.isMammal = false;
console.log(alienCat);

हम उन प्रोटोटाइप को भी संशोधित कर सकते हैं जो कक्षा में निर्मित सभी वस्तुओं को प्रभावित करेंगे।

// All cats are mutated to be non-mammals
Cat.prototype.isMammal = false;
console.log(tiger, alienCat);

मैंने मूल रूप से इस उत्तर के साथ कुछ लिखा था ।


2
ओपी कई प्रोटोटाइप चेन (जैसे childविरासत से parent1और parent2) के लिए पूछ रहा है । आपका उदाहरण केवल एक श्रृंखला के बारे में बात करता है।
पॉशेस्ट

0

सीन में एक लेटकोमर है सिम्पलक्लेयर । हालाँकि, कई उत्तराधिकारियों के साथ व्यवहार करते समय, आप अभी भी मूल रचनाकारों की प्रतियों के साथ समाप्त होंगे। यह जावास्क्रिप्ट में एक आवश्यकता है ...

मर्क।


यह जावास्क्रिप्ट में जरूरी है ... ईएस 6 प्रॉक्सि तक।
जोनाथन

दिलचस्प हैं! मैं निश्चित रूप से SimpleDeclare को बदलते हुए देखूंगा ताकि मानक का हिस्सा बनने के बाद उसे परदे के पीछे की विधियों को कॉपी करने की आवश्यकता न पड़े। SimpleDeclare का कोड वास्तव में, वास्तव में पढ़ने और बदलने में आसान है ...
Merc

0

मैं ds.up का उपयोग करता हूँ । प्रोटोटाइप के समान है। जेएस और अन्य। एकाधिक वंशानुक्रम को बहुत आसान बनाता है और इसका न्यूनतम उपयोग करता है। (केवल 2 या 3 केबी) भी इंटरफेस और निर्भरता इंजेक्शन जैसे कुछ अन्य स्वच्छ सुविधाओं का समर्थन करता है

/*** multiple inheritance example ***********************************/

var Runner = ds.class({
    run: function() { console.log('I am running...'); }
});

var Walker = ds.class({
    walk: function() { console.log('I am walking...'); }
});

var Person = ds.class({
    inherits: [Runner, Walker],
    eat: function() { console.log('I am eating...'); }
});

var person = new Person();

person.run();
person.walk();
person.eat();

0

इसके बारे में कैसे, यह जावास्क्रिप्ट में कई उत्तराधिकार को लागू करता है:

    class Car {
        constructor(brand) {
            this.carname = brand;
        }
        show() {
            return 'I have a ' + this.carname;
        }
    }

    class Asset {
        constructor(price) {
            this.price = price;
        }
        show() {
            return 'its estimated price is ' + this.price;
        }
    }

    class Model_i1 {        // extends Car and Asset (just a comment for ourselves)
        //
        constructor(brand, price, usefulness) {
            specialize_with(this, new Car(brand));
            specialize_with(this, new Asset(price));
            this.usefulness = usefulness;
        }
        show() {
            return Car.prototype.show.call(this) + ", " + Asset.prototype.show.call(this) + ", Model_i1";
        }
    }

    mycar = new Model_i1("Ford Mustang", "$100K", 16);
    document.getElementById("demo").innerHTML = mycar.show();

और यहाँ expert_with () उपयोगिता फ़ंक्शन के लिए कोड है:

function specialize_with(o, S) { for (var prop in S) { o[prop] = S[prop]; } }

यह वास्तविक कोड है जो चलता है। आप इसे html फ़ाइल में कॉपी-पेस्ट कर सकते हैं, और इसे स्वयं आज़मा सकते हैं। यह वास्तव में कारगर है।

यह जावा में एमआई को लागू करने का प्रयास है। कोड का अधिक नहीं, एक और अधिक का पता।

कृपया इस पर मेरा पूरा लेख देखने के लिए स्वतंत्र महसूस करें, https://github.com/latitov/OOP_MI_Ct_oPlus_in_JS


0

मैं सिर्फ यह बताता था कि मुझे दूसरों के गुणों में कौन सी कक्षाएं चाहिए और मैं उन्हें ऑटो-पॉइंट के लिए एक प्रॉक्सी जोड़ सकता हूँ जैसे:

class A {
    constructor()
    {
        this.test = "a test";
    }

    method()
    {
        console.log("in the method");
    }
}

class B {
    constructor()
    {
        this.extends = [new A()];

        return new Proxy(this, {
            get: function(obj, prop) {

                if(prop in obj)
                    return obj[prop];

                let response = obj.extends.find(function (extended) {
                if(prop in extended)
                    return extended[prop];
            });

            return response ? response[prop] : Reflect.get(...arguments);
            },

        })
    }
}

let b = new B();
b.test ;// "a test";
b.method(); // in the method
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.