Как вызвать родительский метод из дочернего класса в javascript?

Я провел последние пару часов, пытаясь найти решение моей проблемы, но кажется, что это безнадежно.

В основном мне нужно знать, как вызвать родительский метод из дочернего класса. Все, что я пробовал до сих пор, заканчивается тем, что он не работает или не переписывает родительский метод.

Я использую следующий код для настройки OOP в 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 methods
ParentObject.prototype = {
    myMethod: function(arg) {
        this.name = arg;
    }
}

// child
function ChildObject(name) {
    // call the parent 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() Но я действительно не могу понять, как это делается в javascript.

Любая помощь очень ценится, спасибо!

Ответ 1

Вот как это делается: ParentClass.prototype.myMethod();

Или если вы хотите вызвать его в контексте текущего экземпляра, вы можете сделать: ParentClass.prototype.myMethod.call(this)

То же самое касается вызова родительского метода из дочернего класса с аргументами: ParentClass.prototype.myMethod.call(this, arg1, arg2, ..) * Подсказка: используйте apply() вместо call() для передачи аргументов в виде массива.

Ответ 2

Стиль ES6 позволяет использовать новые функции, например ключевое слово super. super ключевое слово все о контексте родительского класса, когда вы используете синтаксис классов ES6. В качестве очень простого примера: checkout:

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 и будьте счастливы.

Ответ 3

В случае множественного уровня наследования эта функция может использоваться как метод super() на других языках. Вот демонстрационная скрипта, с некоторыми тестами вы можете использовать ее так: внутри вашего метода используйте: call_base(this, 'method_name', arguments);

Он использует довольно недавние функции ES, совместимость со старыми браузерами не является гарантией. Протестировано в 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);
    }
}

Ответ 4

Как насчет чего-то, основанного на идее Дугласа Крокфорда:

    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

Ответ 5

Хорошо, чтобы сделать это, вы не ограничены абстракцией Class ES6. Доступ к методам прототипа родительского конструктора возможен с помощью свойства __proto__ (я уверен, что будут сторонние JS-кодеры, чтобы жаловаться, что он обесценился), который обесценивается, но в то же время обнаружил, что он на самом деле является важным инструментом для суб- (особенно для задач подклассификации Array). Поэтому, пока свойство __proto__ по-прежнему доступно во всех основных JS-машинах, которые я знаю, ES6 представила Object.getPrototypeOf() функциональность поверх нее, Инструмент super() в абстракции Class является синтаксическим сахаром этого.

Итак, если у вас нет доступа к имени родительского конструктора и вы не хотите использовать абстракцию Class, вы можете сделать следующее:

function ChildObject(name) {
    // call the parent 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);
    }
}