web-dev-qa-db-fra.com

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

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

Fondamentalement, j'ai besoin de savoir comment appeler une méthode parent à partir d'une classe enfant ... Tous les trucs que j'ai essayés jusqu'à présent finissent par ne pas fonctionner ou par écraser la méthode parent.

J'utilise le code suivant pour configurer OOP 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);

Je dois d'abord appeler la méthode du parent, puis lui ajouter des éléments supplémentaires dans la classe enfant.

Dans la plupart des OOP langues, cela serait aussi simple que d'appeler parent.myMethod() Mais je ne peux vraiment pas comprendre comment cela fonctionne en javascript.

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

100
YemSalat

Voici comment cela se fait: ParentClass.prototype.myMethod();

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

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

147
YemSalat

Le style ES6 vous permet d’utiliser de nouvelles fonctionnalités, telles que le mot clé super. Le mot clé super concerne le contexte de la classe parent lorsque vous utilisez la syntaxe des classes ES6. Comme exemple très simple, la caisse:

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

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

De plus, vous pouvez 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 parente super.prop. Utilisez donc ES6 et soyez heureux.

83
Dmytro Medvid

Pour ce faire, vous n'êtes pas limité à l'abstraction Class de ES6. L'accès aux méthodes prototypes du constructeur parent est possible via la propriété __proto__ (je suis presque sûr que d'autres codeurs JS se plaindront de son amortissement), ce qui est amorti tout en découvrant qu'il s'agit en réalité d'un outil essentiel pour les besoins de sous-classement. (surtout pour les besoins en sous-classification Array). Ainsi, bien que la propriété __proto__ soit toujours disponible dans tous les principaux moteurs JS que je connaisse, ES6 a ajouté la fonctionnalité Object.getPrototypeOf() . L'outil super() de l'abstraction Class en est un sucre syntaxique.

Donc, si vous n'avez pas accès au nom du constructeur parent et que vous ne voulez pas utiliser l'abstraction Class, vous pouvez toujours procéder 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);
    }
}
3
Redu

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

Il utilise des fonctions ES assez récentes, une 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);
    }
}
3
weeger

Que diriez-vous de quelque chose basé sur l'idée de Douglas 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
2
Alex

Voici un moyen intéressant pour les objets enfants d'accéder aux propriétés et méthodes parent à l'aide de la chaîne de prototypes de JavaScript, compatible avec Internet Explorer. JavaScript recherche les méthodes dans la chaîne de prototypes et nous souhaitons que la chaîne de prototypes de l’enfant se présente comme suit:

Instance enfant -> Prototype de l’enfant (avec méthodes Child) -> Prototype du parent (avec méthodes Parent) -> Prototype de l’objet -> null

Les méthodes enfant peuvent également appeler des méthodes parent ombrées, comme indiqué aux 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');

0
CaptureWiz

Il existe une solution beaucoup plus simple et plus compacte pour la recherche de prototypes à plusieurs niveaux, mais elle nécessite un support Proxy. Utilisation: SUPER(<instance>).<method>(<args>), par exemple, en supposant que deux classes A et B extends A soient utilisées avec la méthode 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
ZzZombo