जावास्क्रिप्ट में बच्चे की कक्षा से एक मूल विधि कैसे कॉल करें?


156

मैंने अपनी समस्या का हल खोजने की कोशिश करते हुए आखिरी दो घंटे बिताए हैं लेकिन यह निराशाजनक लगता है।

मूल रूप से मुझे यह जानने की जरूरत है कि बच्चे की कक्षा से माता-पिता की विधि कैसे कॉल करें। मेरे द्वारा अब तक कोशिश की गई सभी चीजें या तो काम नहीं कर रही हैं या मूल विधि को ओवर राइटिंग नहीं कर रही हैं।

मैं जावास्क्रिप्ट में 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() लेकिन मैं वास्तव में समझ नहीं पा रहा हूं कि इसका जावास्क्रिप्ट में क्या किया गया है।

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

जवाबों:


196

यहां बताया गया है कि कैसे किया जाता है: ParentClass.prototype.myMethod();

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

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


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

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

मुझे समझ नहीं आ रहा है। अगर मैं ParentClass.prototyp.myMethod.call (यह) कहता हूं; चाइल्डऑबजेक्ट के myMethod से, मुझे एक त्रुटि मिली है "अनकैप्ड टाइपर्रर: अपरिभाषित की संपत्ति 'कॉल' नहीं पढ़ सकता है"।
ज़ेकॉउस

@ ज़ेकौस, इसका मतलब होगा कि आपके पास myMethodआपकी कक्षा नहीं है ।
यमसत

2
मैं वर्तमान में this.myFun = function () {} का उपयोग किसी ऑब्जेक्ट विधि को घोषित करने के लिए कर रहा हूं, इसलिए ParentClass.prototyp.myFun.call (...) पर काम नहीं कर रहा है, इसलिए मुझे CurrentClass.prototyp.myFun.call (का उपयोग करना होगा) ...)। जेएस है ... एक बकवास, हमें वास्तविक ओओपी का उपयोग करना चाहिए।
Loenix

156

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 का उपयोग करें और खुश रहें।


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

यह तरीकों कि स्थिर नहीं होते हैं के लिए भी काम करता है (क्रोम के साथ परीक्षण किया, कोई transpiliing साथ, स्थिर कीवर्ड tryed नहीं)
जाएनलुका Casati

इसे superबुलाने की आवश्यकता क्यों है ? क्या "पुराने" जेएस में कोई समानता है?
१२५२ --४48

3
सुपर () को कुछ भी करने से पहले बच्चे के क्लास कंस्ट्रक्टर में बुलाया जाना चाहिए।
user938363

1
@GianlucaCasati: आप केवल super()स्थैतिक तरीकों का उपयोग कर सकते हैं ; ऐसा लगता है कि आपने इसे कंस्ट्रक्टर में उपयोग किया है।
ZZZombo

5

वैसे ऐसा करने के लिए, आप Classईएस 6 के अमूर्त के साथ सीमित नहीं हैं । __proto__संपत्ति के माध्यम से मूल निर्माता के प्रोटोटाइप तरीकों तक पहुंच संभव है (मुझे पूरा यकीन है कि साथी जेएस कोडर्स को शिकायत करना होगा कि यह मूल्यह्रास है) जो कि मूल्यह्रास है, लेकिन साथ ही यह पता चला कि यह वास्तव में उप-वर्गीय जरूरतों के लिए एक आवश्यक उपकरण है ( विशेष रूप से ऐरे सब-क्लासिंग जरूरतों के लिए हालांकि)। इसलिए जबकि __proto__संपत्ति अभी भी सभी प्रमुख जेएस इंजनों में उपलब्ध है जो मुझे पता है, ईएस 6 ने इसके Object.getPrototypeOf()शीर्ष पर कार्यक्षमता पेश की । super()में उपकरण 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);
    }
}

4

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

यह काफी हालिया ईएस कार्यों का उपयोग करता है, पुराने ब्राउज़रों के साथ संगतता की गारंटी नहीं है। IE11, FF29, CH35 में परीक्षण किया गया।

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

2

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

    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

2

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

बाल उदाहरण -> बाल प्रोटोटाइप (बाल विधियों के साथ) -> माता-पिता का प्रोटोटाइप (माता-पिता के तरीकों के साथ) -> वस्तु प्रोटोटाइप>> सुस्त

बाल विधियां भी छाया अभिभावक विधियों को कह सकती हैं, जैसा कि तीन तारांकन नीचे दिखाया गया है।

ऐसे:

//Parent constructor
function ParentConstructor(firstName){
    //add parent properties:
    this.parentProperty = firstName;
}

//add 2 Parent methods:
ParentConstructor.prototype.parentMethod = function(argument){
    console.log(
            "Parent says: argument=" + argument +
            ", parentProperty=" + this.parentProperty +
            ", childProperty=" + this.childProperty
    );
};

ParentConstructor.prototype.commonMethod = function(argument){
    console.log("Hello from Parent! argument=" + argument);
};

//Child constructor    
function ChildConstructor(firstName, lastName){
    //first add parent's properties
    ParentConstructor.call(this, firstName);

    //now add child's properties:
    this.childProperty = lastName;
}

//insert Parent's methods into Child's prototype chain
var rCopyParentProto = Object.create(ParentConstructor.prototype);
rCopyParentProto.constructor = ChildConstructor;
ChildConstructor.prototype = rCopyParentProto;

//add 2 Child methods:
ChildConstructor.prototype.childMethod = function(argument){
    console.log(
            "Child says: argument=" + argument +
            ", parentProperty=" + this.parentProperty +
            ", childProperty=" + this.childProperty
    );
};

ChildConstructor.prototype.commonMethod = function(argument){
    console.log("Hello from Child! argument=" + argument);

    // *** call Parent's version of common method
    ParentConstructor.prototype.commonMethod(argument);
};

//create an instance of Child
var child_1 = new ChildConstructor('Albert', 'Einstein');

//call Child method
child_1.childMethod('do child method');

//call Parent method
child_1.parentMethod('do parent method');

//call common method
child_1.commonMethod('do common method');


1

मल्टीलेवल प्रोटोटाइप लुकअप के लिए बहुत आसान और अधिक कॉम्पैक्ट समाधान है, लेकिन इसके लिए Proxyसमर्थन की आवश्यकता है । उपयोग: SUPER(<instance>).<method>(<args>), उदाहरण के लिए, दो वर्गों संभालने के लिए Aऔर B extends Aविधि के साथ m: SUPER(new B).m()

function SUPER(instance) {
    return new Proxy(instance, {
        get(target, prop) {
            return Object.getPrototypeOf(Object.getPrototypeOf(target))[prop].bind(target);
        }
    });
}

0

आप माता-पिता के प्रोटोटाइप से माता-पिता विधि कॉल कर सकते हैं, आप प्रयोग करने के लिए वर्तमान बच्चे उदाहरण पारित करने के लिए की आवश्यकता होगी call, applyया bindविधि। bindतो मैं सिफारिश नहीं करता है कि अगर आप इसे छोड़कर प्रदर्शन के लिए देखभाल केवल एक बार कहा जाता विधि एक नया कार्य पैदा करेगा।

विकल्प के रूप में आप चाइल्ड मेथड को रिप्लेस कर सकते हैं और ओरिजिनल चाइल्ड मेथड को कॉल करते समय पेरेंट मेथड को इंस्टाल कर सकते हैं।

function proxy(context, parent){
  var proto = parent.prototype;
  var list = Object.getOwnPropertyNames(proto);
  
  var child = {};
  for(var i=0; i<list.length; i++){
    var key = list[i];

    // Create only when child have similar method name
    if(context[key] !== proto[key]){
      child[key] = context[key];
      context[key] = function(){
        context.super = proto[key];
        return child[key].apply(context, arguments);
      }
    }
  }
}

// ========= The usage would be like this ==========

class Parent {
  first = "Home";

  constructor(){
    console.log('Parent created');
  }

  add(arg){
    return this.first + ", Parent "+arg;
  }
}

class Child extends Parent{
  constructor(b){
    super();
    proxy(this, Parent);
    console.log('Child created');
  }

  // Comment this to call method from parent only
  add(arg){
    return this.super(arg) + ", Child "+arg;
  }
}

var family = new Child();
console.log(family.add('B'));

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