2012-08-07 27 views
80

मैंने पिछले कुछ घंटों में अपनी समस्या का हल ढूंढने की कोशिश की है लेकिन यह निराशाजनक प्रतीत होता है।जावास्क्रिप्ट में बाल वर्ग से अभिभावक विधि को कैसे कॉल करें?

मूल रूप से मुझे यह जानने की ज़रूरत है कि एक बाल वर्ग से अभिभावक विधि को कैसे कॉल करें। सभी चीजें जो मैंने अभी तक कोशिश की है, वे या तो काम नहीं कर रहे हैं या माता-पिता विधि को ओवर-लेखन नहीं कर रहे हैं।

मैं जावास्क्रिप्ट में OOP स्थापित करने के लिए निम्न कोड का उपयोग कर रहा:

// SET UP OOP 
// surrogate constructor (empty function) 
function surrogateCtor() {} 

function extend(base, sub) { 
    // copy the prototype from the base to setup inheritance 
    surrogateCtor.prototype = base.prototype; 
    sub.prototype = new surrogateCtor(); 
    sub.prototype.constructor = sub; 
} 

// parent class 
function ParentObject(name) { 
    this.name = name; 
} 
// parent's methods 
ParentObject.prototype = { 
    myMethod: function(arg) { 
     this.name = arg; 
    } 
} 

// child 
function ChildObject(name) { 
    // call the parent's constructor 
    ParentObject.call(this, name); 
    this.myMethod = function(arg) { 
     // HOW DO I CALL THE PARENT METHOD HERE? 
     // do stuff 
    } 
} 

// setup the prototype chain 
extend(ParentObject, ChildObject); 

मैं माता पिता की विधि पहले फोन और उसके बाद बच्चे कक्षा में इसे करने के लिए कुछ और सामान जोड़ने की जरूरत है।

अधिकांश ओओपी भाषाओं में जो parent.myMethod() पर कॉल करने जितना आसान होगा, लेकिन मैं वास्तव में यह समझ नहीं पा रहा हूं कि यह जावास्क्रिप्ट में कैसे किया गया।

किसी भी मदद की बहुत सराहना की है, धन्यवाद!

उत्तर

123

यहाँ कैसे अपने किया है: ParentClass.prototype.myMethod();

या यदि आप वर्तमान उदाहरण के संदर्भ में यह कॉल करना चाहते हैं, तो आप कर सकते हैं: ParentClass.prototype.myMethod.call(this)

एक ही साथ बच्चे कक्षा से एक माता पिता विधि फोन करने के लिए चला जाता है तर्क: ParentClass.prototype.myMethod.call(this, arg1, arg2, ..) * संकेत: apply() का उपयोग call() के बजाय एक सरणी के रूप में तर्क पारित करने के लिए करें।

+7

आप वर्तमान उदाहरण के संदर्भ में यह कॉल करना चाहते हैं, तो आप) 'क्या करना ParentClass.prototype.myMethod.apply (है) या' ParentClass.prototype.myMethod.call (', जैसे आप करते हैं आपके कन्स्ट्रक्टर के साथ। – JMM

+3

अगर आप तर्कों के साथ कॉल करना चाहते हैं तो बस इसमें शामिल होने के बाद, वे लागू या कॉल फ़ंक्शन ('ParentClass.prototype.myMethod.call (यह, arg1, arg2, arg3 ...) के अंदर जाते हैं; ') –

+0

मैं नहीं करता समझना। अगर मैं ParentClass.prototype.myMethod.call (यह) को कॉल करता हूं; ChildObject के myMethod से, मुझे एक त्रुटि मिली है "Uncaught TypeError: अपरिभाषित की संपत्ति 'कॉल' नहीं पढ़ सकता है। – zhekaus

2

एकाधिक विरासत स्तर के मामले में, इस फ़ंक्शन को अन्य भाषाओं में एक सुपर() विधि के रूप में उपयोग किया जा सकता है। Here is a demo fiddle, कुछ परीक्षणों के साथ, आप इसे अपने विधि के उपयोग के अंदर उपयोग कर सकते हैं: call_base(this, 'method_name', arguments);

यह हाल ही के ईएस कार्यों का उपयोग करता है, पुराने ब्राउज़र के साथ संगतता गारंटी नहीं है। आईई 11, एफएफ 2 9, सीएच 35 में परीक्षण किया गया।

/** 
* Call super method of the given object and method. 
* This function create a temporary variable called "_call_base_reference", 
* to inspect whole inheritance linage. It will be deleted at the end of inspection. 
* 
* Usage : Inside your method use call_base(this, 'method_name', arguments); 
* 
* @param {object} object The owner object of the method and inheritance linage 
* @param {string} method The name of the super method to find. 
* @param {array} args The calls arguments, basically use the "arguments" special variable. 
* @returns {*} The data returned from the super method. 
*/ 
function call_base(object, method, args) { 
    // We get base object, first time it will be passed object, 
    // but in case of multiple inheritance, it will be instance of parent objects. 
    var base = object.hasOwnProperty('_call_base_reference') ? object._call_base_reference : object, 
    // We get matching method, from current object, 
    // this is a reference to define super method. 
      object_current_method = base[method], 
    // Temp object wo receive method definition. 
      descriptor = null, 
    // We define super function after founding current position. 
      is_super = false, 
    // Contain output data. 
      output = null; 
    while (base !== undefined) { 
     // Get method info 
     descriptor = Object.getOwnPropertyDescriptor(base, method); 
     if (descriptor !== undefined) { 
      // We search for current object method to define inherited part of chain. 
      if (descriptor.value === object_current_method) { 
       // Further loops will be considered as inherited function. 
       is_super = true; 
      } 
      // We already have found current object method. 
      else if (is_super === true) { 
       // We need to pass original object to apply() as first argument, 
       // this allow to keep original instance definition along all method 
       // inheritance. But we also need to save reference to "base" who 
       // contain parent class, it will be used into this function startup 
       // to begin at the right chain position. 
       object._call_base_reference = base; 
       // Apply super method. 
       output = descriptor.value.apply(object, args); 
       // Property have been used into super function if another 
       // call_base() is launched. Reference is not useful anymore. 
       delete object._call_base_reference; 
       // Job is done. 
       return output; 
      } 
     } 
     // Iterate to the next parent inherited. 
     base = Object.getPrototypeOf(base); 
    } 
} 
0

कुछ डगलस Crockford विचार पर आधारित के बारे में कैसे:

function Shape(){} 

    Shape.prototype.name = 'Shape'; 

    Shape.prototype.toString = function(){ 
     return this.constructor.parent 
      ? this.constructor.parent.toString() + ',' + this.name 
      : this.name; 
    }; 


    function TwoDShape(){} 

    var F = function(){}; 

    F.prototype = Shape.prototype; 

    TwoDShape.prototype = new F(); 

    TwoDShape.prototype.constructor = TwoDShape; 

    TwoDShape.parent = Shape.prototype; 

    TwoDShape.prototype.name = '2D Shape'; 


    var my = new TwoDShape(); 

    console.log(my.toString()); ===> Shape,2D Shape 
36

ES6 शैली आप नई सुविधाओं का उपयोग करने की अनुमति देता है, इस तरह super कीवर्ड के रूप में। super कीवर्ड यह सब कुछ मूल वर्ग संदर्भ के बारे में है, जब आप ES6 कक्षा वाक्यविन्यास का उपयोग कर रहे हैं। एक बहुत ही सरल उदाहरण, चेकआउट के रूप में:

class Foo { 
    static classMethod() { 
     return 'hello'; 
    } 
} 

class Bar extends Foo { 
    static classMethod() { 
     return super.classMethod() + ', too'; 
    } 
} 
Bar.classMethod(); // 'hello, too' 

इसके अलावा, आप माता-पिता निर्माता कॉल करने के लिए super उपयोग कर सकते हैं:

class Foo {} 

class Bar extends Foo { 
    constructor(num) { 
     let tmp = num * 2; // OK 
     this.num = num; // ReferenceError 
     super(); 
     this.num = num; // OK 
    } 
} 

और निश्चित रूप से आप माता-पिता वर्ग गुण super.prop तक पहुँचने के लिए उपयोग कर सकते हैं। तो, ES6 का उपयोग करें और खुश रहें।

+1

इस उत्तर में अधिक upvotes क्यों नहीं है? :) – fsinisi90

+2

@ fsinisi90 मेरा मानना ​​है कि सवाल माता-पिता के वर्ग विधियों के बारे में नहीं है, बल्कि माता-पिता के उदाहरण विधियों के बारे में नहीं है जिन्हें केवल सुपर 6 के रूप में सुपर कीवर्ड के साथ नहीं कहा जा सकता है। – mcmlxxxiii

+0

यह उन विधियों के लिए भी काम करता है जो स्थैतिक नहीं हैं (क्रोम के साथ परीक्षण किया गया है, बिना पारदर्शी के, स्थिर कीवर्ड का प्रयास नहीं किया गया है) –

0

अच्छा करने के लिए, आप Class ES6 के अमूर्तता तक सीमित नहीं हैं। __proto__ संपत्ति के माध्यम से अभिभावक कन्स्ट्रक्टर के प्रोटोटाइप विधियों तक पहुंच संभव है (मुझे पूरा यकीन है कि साथी जेएस कोडर शिकायत करेंगे कि यह अवमूल्यन है) जो कि अवमूल्यन है लेकिन साथ ही यह पता चला है कि यह वास्तव में उप-वर्गीकरण आवश्यकताओं के लिए एक आवश्यक उपकरण है (विशेष रूप से ऐरे उप-वर्गीकरण की आवश्यकता के लिए)।इसलिए __proto__ संपत्ति अभी भी उन सभी प्रमुख जेएस इंजनों में उपलब्ध है जो मुझे पता है, ईएस 6 ने इसके ऊपर Object.getPrototypeOf() कार्यक्षमता पेश की है। Class अमूर्तता में उपकरण इस की एक वाक्य रचनात्मक चीनी है।

इसलिए यदि आपके पास मूल निर्माता के नाम तक पहुंच नहीं है और Class अमूर्तता का उपयोग नहीं करना चाहते हैं तो भी आप निम्नानुसार कर सकते हैं;

function ChildObject(name) { 
    // call the parent's constructor 
    ParentObject.call(this, name); 
    this.myMethod = function(arg) { 
    //this.__proto__.__proto__.myMethod.call(this,arg); 
    Object.getPrototypeOf(Object.getPrototypeOf(this)).myMethod.call(this,arg); 
    } 
}