Как вызвать родительский метод из дочернего класса в 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);
}
}