252 votes

Comment appeler une méthode parent depuis une classe enfant en javascript ?

J'ai passé les deux dernières heures à essayer de trouver une solution à mon problème, mais cela semble être sans espoir.

En fait, j'ai besoin de savoir comment appeler une méthode parentale depuis une classe enfant. Tout ce que j'ai essayé jusqu'à présent ne fonctionne pas ou écrase la méthode parentale.

J'utilise le code suivant pour mettre en place la POO en javascript :

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

J'ai besoin d'appeler la méthode du parent d'abord, puis d'y ajouter d'autres éléments dans la classe enfant.

Dans la plupart des langages de programmation opérationnelle, il suffirait d'appeler parent.myMethod() Mais je n'arrive vraiment pas à comprendre comment cela se fait en javascript.

Toute aide est très appréciée, merci !

285voto

Jenezis Points 1

Le style ES6 vous permet d'utiliser de nouvelles fonctionnalités, telles que super mot-clé. super mot-clé tout est question de contexte de classe parent, lorsque vous utilisez la syntaxe des classes ES6. Comme exemple très simple, vérifiez :

Rappelez-vous : Nous ne pouvons pas invoquer les méthodes statiques parentales via super à l'intérieur d'une méthode d'instance. La méthode d'appel doit également être statique.

Invocation d'une méthode statique via une méthode d'instance - TypeError !

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

class Bar extends Foo {
  classMethod() {
    return super.classMethod() + ', too';
  }
}
console.log(Bar.classMethod()); // 'hello' - Invokes inherited static method
console.log((new Bar()).classMethod()); // 'Uncaught TypeError' - Invokes on instance method

Invocation d'une méthode statique via super - Ça marche !

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

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

console.log(Bar.classMethod()); // 'hello, too'

Maintenant super le contexte change en fonction de l'invocation - Voilà !

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

  classMethod() {
    return 'hello there i am an instance ';
  }
}

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

console.log((new Bar()).classMethod()); // "hello there i am an instance , too"
console.log(Bar.classMethod()); // "hello i am static only"

Vous pouvez également utiliser super pour appeler le constructeur parent :

class Foo {}

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

Et bien sûr, vous pouvez l'utiliser pour accéder aux propriétés de la classe mère super.prop . Alors, utilisez ES6 et soyez heureux.

244voto

YemSalat Points 1198

Voici comment procéder : ParentClass.prototype.myMethod();

Ou si vous voulez l'appeler dans le contexte de l'instance actuelle, vous pouvez le faire : ParentClass.prototype.myMethod.call(this)

Il en va de même pour l'appel d'une méthode parent depuis une classe enfant avec des arguments : ParentClass.prototype.myMethod.call(this, arg1, arg2, ..) * Conseil : utilisez apply() au lieu de call() pour passer des arguments sous forme de tableau.

8voto

Redu Points 11722

Eh bien, pour ce faire, vous n'êtes pas limité avec les Class abstraction de l'ES6. L'accès aux méthodes du prototype du constructeur parent est possible grâce à la fonction __proto__ (je suis sûr qu'il y aura des collègues codeurs JS pour se plaindre qu'elle est dépréciée) qui est dépréciée mais en même temps, on a découvert qu'elle est en fait un outil essentiel pour les besoins de sous-classement (surtout pour les besoins de sous-classement des tableaux). Ainsi, alors que le __proto__ est toujours disponible dans tous les principaux moteurs JS que je connais, ES6 a introduit la propriété Object.getPrototypeOf() par-dessus. Le site super() dans l'outil Class L'abstraction est un sucre syntaxique de ceci.

Ainsi, si vous n'avez pas accès au nom du constructeur parent et que vous ne souhaitez pas utiliser l'attribut Class abstraction, vous pouvez toujours faire comme suit ;

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

5voto

CaptureWiz Points 598

Voici un moyen agréable pour les objets enfants d'avoir accès aux propriétés et méthodes du parent en utilisant la chaîne de prototypes de JavaScript, et il est compatible avec Internet Explorer. JavaScript recherche les méthodes dans la chaîne des prototypes et nous voulons que la chaîne des prototypes de l'enfant ressemble à ceci :

instance de l'enfant -> prototype de l'enfant (avec les méthodes de l'enfant) -> prototype du parent (avec les méthodes du parent) -> prototype de l'objet -> null

Les méthodes enfant peuvent également appeler des méthodes parentales cachées, comme le montrent les trois astérisques *** ci-dessous.

Voici comment :

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

4voto

weeger Points 126

En cas de niveau d'héritage multiple, cette fonction peut être utilisée comme une méthode super() dans d'autres langues. Voici un violon de démonstration Avec quelques tests, vous pouvez l'utiliser comme suit : dans votre méthode, utilisez : call_base(this, 'method_name', arguments);

Il utilise des fonctions ES très récentes, et la compatibilité avec les navigateurs plus anciens n'est pas garantie. Testé dans 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);
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X