जावास्क्रिप्ट प्रोटोटाइप का उपयोग करके कॉलिंग विधि


129

यदि इसे ओवरराइड किया गया है, तो क्या जावास्क्रिप्ट में एक प्रोटोटाइप विधि से आधार विधि को कॉल करना संभव है?

MyClass = function(name){
    this.name = name;
    this.do = function() {
        //do somthing 
    }
};

MyClass.prototype.do = function() {  
    if (this.name === 'something') {
        //do something new
    } else {
        //CALL BASE METHOD
    }
};

आधार विधि कौन सी है? इस। कार्य = () {} कंस्ट्रक्टर में?
इओनु 12: जी। स्टेन

जवाबों:


200

मुझे समझ नहीं आया कि आप वास्तव में क्या करने की कोशिश कर रहे हैं, लेकिन आम तौर पर वस्तु-विशिष्ट व्यवहार को लागू करना इन पंक्तियों के साथ किया जाता है:

function MyClass(name) {
    this.name = name;
}

MyClass.prototype.doStuff = function() {
    // generic behaviour
}

var myObj = new MyClass('foo');

var myObjSpecial = new MyClass('bar');
myObjSpecial.doStuff = function() {
    // do specialised stuff
    // how to call the generic implementation:
    MyClass.prototype.doStuff.call(this /*, args...*/);
}

1
मुझे यह नहीं मिलता है, मैं यहाँ बिल्कुल उसी उद्देश्य के लिए आया था जैसे कि markvpc। मेरा मतलब है, मैं एक "निजी" विधि का उपयोग करना चाहता हूं जो कि प्रोटोटाइप में अन्य तरीकों से उपयोग किया जाता है। आपकी प्रतिक्रिया मुझे एक कारखाना बनाने के लिए मजबूर करती है और मैं जानना चाहता हूं कि क्या इससे बचने का कोई तरीका है।
R01010010

10
जेएस में "क्लास" शब्दों का उपयोग न करें क्योंकि यह भ्रम पैदा करता है। जावास्क्रिप्ट में कक्षाएं नहीं हैं
पोलारिस

1
यह केवल तात्कालिक वस्तुओं के लिए काम करता है। क्या होगा यदि आप सभी उदाहरणों को ओवरराइड करना चाहते हैं?
सुपरटॉन्स्की

मेरे लिये कार्य करता है! बिल्कुल वही जो मुझे चाहिए था। मेरे पास 4 कंस्ट्रक्टर हैं जो एक माता-पिता से विरासत में मिले हैं। उनमें से दो को बेस कंस्ट्रक्टर पर एक विधि को ओवरराइड और कॉल करने की आवश्यकता है जो उनका प्रोटोटाइप है। इसने मुझे ठीक वैसा ही होने दिया।
बाइनरीजेंट जूल

3
मुझे समझ में नहीं आता है कि यह इतने सारे अपवित्र क्यों हैं और इसे सही के रूप में चिह्नित किया गया है। यह केवल बेस-क्लास के एक उदाहरण के लिए व्यवहार को ओवरराइड करता है, सब-क्लास के सभी उदाहरणों को नहीं। इस प्रकार यह प्रश्न का उत्तर नहीं देता है।
ब्लूराजा - डैनी पफ्लुगुएफ्ट

24

ऐसा करने का एक तरीका आधार विधि को सहेजना और फिर इसे ओवरराइड विधि से कॉल करना होगा, जैसे कि

MyClass.prototype._do_base = MyClass.prototype.do;
MyClass.prototype.do = function(){  

    if (this.name === 'something'){

        //do something new

    }else{
        return this._do_base();
    }

};

11
इससे अनंत पुनरावृत्ति होगी।
जोहान टिडेन

3
मैं वहाँ गया था: अनंत पुनरावर्तन।
जपेली

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

10
@ जोहानिडेन _do_baseपहले जो भी फ़ंक्शन परिभाषित किया गया था, उसका संदर्भ देता है। अगर कोई नहीं था, तो यह होगा undefined। जावास्क्रिप्ट नहीं है make-एक्सप्रेसेंस का कभी भी आलसी मूल्यांकन नहीं किया जाता है जैसे आप सुझाव देते हैं कि वे हैं। अब, अगर प्रोटोटाइप से विरासत में मिला जा रहा है भी स्टोर करने के लिए इस्तेमाल किया _do_base क्या यह सोचता है की इसके आधार प्रकार का क्रियान्वयन है do, तो आप एक समस्या है। तो, हाँ, इस पद्धति का उपयोग करते समय मूल फ़ंक्शन कार्यान्वयन के संदर्भ को संग्रहीत करने के लिए एक बंद, एक बेहतर, विरासत-सुरक्षित तरीका होगा - हालांकि इसका उपयोग करने की आवश्यकता होगी Function.prototype.call(this)
बिंकी

16

मुझे डर है कि आपका उदाहरण आपके सोचने के तरीके पर काम नहीं करता है। यह भाग:

this.do = function(){ /*do something*/ };

की परिभाषा को ओवरराइट करता है

MyClass.prototype.do = function(){ /*do something else*/ };

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

जावास्क्रिप्ट में विरासत का शास्त्रीय रूप अजीब है, और पकड़ना मुश्किल है। मैं इसके बजाय डगलस क्रॉकफोर्ड सरल विरासत पैटर्न का उपयोग करने का सुझाव दूंगा। ऐशे ही:

function my_class(name) {
    return {
        name: name,
        do: function () { /* do something */ }
    };
}

function my_child(name) {
    var me = my_class(name);
    var base_do = me.do;
    me.do = function () {
        if (this.name === 'something'){
            //do something new
        } else {
            base_do.call(me);
        }
    }
    return me;
}

var o = my_child("something");
o.do(); // does something new

var u = my_child("something else");
u.do(); // uses base function

मेरी राय में, जावास्क्रिप्ट में ऑब्जेक्ट्स, कंस्ट्रक्टर और विरासत को संभालने का एक बहुत स्पष्ट तरीका है। आप Crockfords Javascript: अच्छे भागों में अधिक पढ़ सकते हैं ।


3
वास्तव में बहुत अच्छा है, लेकिन आप वास्तव base_doमें एक फ़ंक्शन के रूप में नहीं बुला सकते हैं , क्योंकि आप thisमूल doतरीके से किसी भी बंधन को खो देते हैं । तो, आधार विधि का सेटअप थोड़ा अधिक जटिल है, खासकर यदि आप इसे आधार वस्तु का उपयोग करके thisबच्चे वस्तु के बजाय कॉल करना चाहते हैं । मैं कुछ सुझाव देना चाहूंगा base_do.apply(me, arguments)
Giulio Piancastelli

बस सोच रहा है, क्यों आप का उपयोग नहीं करते varके लिए base_do? यह उद्देश्य पर है और, यदि हां, तो क्यों? और, जैसा @GiulioPiancastelli ने कहा, क्या यह कॉल thisबाध्यकारी है base_do()या क्या यह कॉल thisइसके कॉलर से इनहेरिट करेगा ?
बिंकी

@binki मैंने उदाहरण को अद्यतन किया। varवहाँ होना चाहिए। उपयोग call(या apply) हमें thisठीक से बाँधने की अनुमति देता है ।
मगंर

10

मुझे पता है कि यह पोस्ट 4 साल पहले की है, लेकिन मेरी सी # पृष्ठभूमि के कारण मैं बेस क्लास को कॉल करने का एक तरीका खोज रहा था, जिसमें क्लास के नाम को निर्दिष्ट किए बिना उपवर्ग पर एक संपत्ति द्वारा प्राप्त किया जा सकता था। इसलिए क्रिस्टोफ के जवाब में मेरा एकमात्र बदलाव होगा

इस से:

MyClass.prototype.doStuff.call(this /*, args...*/);

इसके लिए:

this.constructor.prototype.doStuff.call(this /*, args...*/);

6
ऐसा न करें, this.constructorहमेशा इंगित नहीं कर सकते हैं MyClass
बरगी

ठीक है, यह तब तक होना चाहिए, जब तक कि किसी ने विरासत को स्थापित करने से पंगा नहीं लिया। 'यह' हमेशा शीर्ष स्तर की वस्तु को संदर्भित करना चाहिए, और इसकी 'निर्माता' संपत्ति को हमेशा अपने स्वयं के निर्माण कार्य को इंगित करना चाहिए।
त्रिनको

5

यदि आप इस तरह एक समारोह को परिभाषित करते हैं (OOP का उपयोग करके)

function Person(){};
Person.prototype.say = function(message){
   console.log(message);
}

प्रोटोटाइप फ़ंक्शन को कॉल करने के दो तरीके हैं: 1) एक उदाहरण बनाएं और ऑब्जेक्ट फ़ंक्शन को कॉल करें:

var person = new Person();
person.say('hello!');

और दूसरा तरीका है ... 2) फ़ंक्शन को सीधे प्रोटोटाइप से बुला रहा है:

Person.prototype.say('hello there!');

5

इस समाधान का उपयोग करता है Object.getPrototypeOf

TestA सुपर है कि है getName

TestBएक बच्चे को ओवरराइड करता है getNameलेकिन, यह भी है getBothNamesकि कॉल superके संस्करण getNameके साथ-साथ childसंस्करण

function TestA() {
  this.count = 1;
}
TestA.prototype.constructor = TestA;
TestA.prototype.getName = function ta_gn() {
  this.count = 2;
  return ' TestA.prototype.getName is called  **';
};

function TestB() {
  this.idx = 30;
  this.count = 10;
}
TestB.prototype = new TestA();
TestB.prototype.constructor = TestB;
TestB.prototype.getName = function tb_gn() {
  return ' TestB.prototype.getName is called ** ';
};

TestB.prototype.getBothNames = function tb_gbn() {
  return Object.getPrototypeOf(TestB.prototype).getName.call(this) + this.getName() + ' this object is : ' + JSON.stringify(this);
};

var tb = new TestB();
console.log(tb.getBothNames());


4
function NewClass() {
    var self = this;
    BaseClass.call(self);          // Set base class

    var baseModify = self.modify;  // Get base function
    self.modify = function () {
        // Override code here
        baseModify();
    };
}

4

एक विकल्प :

// shape 
var shape = function(type){
    this.type = type;
}   
shape.prototype.display = function(){
    console.log(this.type);
}
// circle
var circle = new shape('circle');
// override
circle.display = function(a,b){ 
    // call implementation of the super class
    this.__proto__.display.apply(this,arguments);
}

काम करने के बावजूद, मैं इस समाधान की सिफारिश नहीं करूंगा। उपयोग करने के कई कारण हैं __proto__(जिससे किसी वस्तु का [[प्रोटोटाइप]] `बदल जाता है) बचना चाहिए। कृपया Object.create(...)इसके बजाय मार्ग का उपयोग करें ।
कर्लग डे

2

अगर मैं सही तरीके से समझूं, तो आप चाहते हैं कि बेस फंक्शनलिटी हमेशा की जाए, जबकि इसका एक टुकड़ा इम्प्लीमेंटेशन पर छोड़ दिया जाए।

आपको ' टेम्प्लेट विधि ' डिज़ाइन पैटर्न द्वारा मदद मिल सकती है ।

Base = function() {}
Base.prototype.do = function() { 
    // .. prologue code
    this.impldo(); 
    // epilogue code 
}
// note: no impldo implementation for Base!

derived = new Base();
derived.impldo = function() { /* do derived things here safely */ }

1

यदि आप अपने सुपर क्लास को नाम से जानते हैं, तो आप ऐसा कुछ कर सकते हैं:

function Base() {
}

Base.prototype.foo = function() {
  console.log('called foo in Base');
}

function Sub() {
}

Sub.prototype = new Base();

Sub.prototype.foo = function() {
  console.log('called foo in Sub');
  Base.prototype.foo.call(this);
}

var base = new Base();
base.foo();

var sub = new Sub();
sub.foo();

यह छपेगा

called foo in Base
called foo in Sub
called foo in Base

जैसा सोचा था।


1

ईएस 5 के साथ एक और तरीका है कि विस्फोटक श्रृंखला का उपयोग करते हुए विस्फोटक तरीके से पार किया जाए Object.getPrototypeOf(this)

const speaker = {
  speak: () => console.log('the speaker has spoken')
}

const announcingSpeaker = Object.create(speaker, {
  speak: {
    value: function() {
      console.log('Attention please!')
      Object.getPrototypeOf(this).speak()
    }
  }
})

announcingSpeaker.speak()

0

नहीं, आपको कंस्ट्रक्टर में डू फंक्शन देना होगा और प्रोटोटाइप को अलग-अलग नामों से करना होगा।


0

इसके अलावा, यदि आप सभी उदाहरणों को ओवरराइड करना चाहते हैं और न कि केवल एक विशेष उदाहरण, यह एक मदद कर सकता है।

function MyClass() {}

MyClass.prototype.myMethod = function() {
  alert( "doing original");
};
MyClass.prototype.myMethod_original = MyClass.prototype.myMethod;
MyClass.prototype.myMethod = function() {
  MyClass.prototype.myMethod_original.call( this );
  alert( "doing override");
};

myObj = new MyClass();
myObj.myMethod();

परिणाम:

doing original
doing override

-1
function MyClass() {}

MyClass.prototype.myMethod = function() {
  alert( "doing original");
};
MyClass.prototype.myMethod_original = MyClass.prototype.myMethod;
MyClass.prototype.myMethod = function() {
  MyClass.prototype.myMethod_original.call( this );
  alert( "doing override");
};

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