我花了几个小时试图找到解决问题的办法,但似乎毫无希望。
基本上,我需要知道如何从子类调用父方法。
到目前为止,我所尝试的所有东西都以无效或重写父方法而告终。
我使用下面的代码在javascript中设置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);
我需要先调用父方法,然后在子类中添加一些更多的东西。
在大多数OOP语言中,调用parent.myMethod()就可以了
但我真的不能理解它是如何在javascript中完成的。
任何帮助都非常感激,谢谢!
虽然您可以通过父方法的原型调用父方法,但您将需要传递当前的子实例以使用调用、应用或绑定方法。bind方法会创建一个新函数,所以如果你关心性能,我不建议你这样做,除非它只被调用一次。
作为一种替代方法,您可以替换子方法,并在调用原始子方法时将父方法放在实例上。
function proxy(context, parent){
var proto = parent.prototype;
var list = Object.getOwnPropertyNames(proto);
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]){
let currentMethod = context[key];
let parentMethod = proto[key];
context[key] = function(){
context.super = parentMethod;
return currentMethod.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 super.add(arg) + ", Child "+arg;
}
}
var family = new Child();
console.log(family.add('B'));
在多重继承级别的情况下,此函数可以在其他语言中用作super()方法。这是一个演示,一些测试,你可以这样使用它,在你的方法使用:call_base(this, 'method_name',参数);
它使用了最新的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);
}
}
ES6风格允许您使用新功能,如超级关键字。super关键字,当你使用ES6类语法时,它都是关于父类上下文的。作为一个非常简单的例子,签出:
记住:我们不能通过实例方法中的super关键字调用父静态方法。调用方法也应该是静态的。
通过实例方法调用静态方法- TypeError !
类Foo {
static classMethod() {
返回“你好”;
}
}
类Bar扩展Foo {
classMethod () {
return super.classMethod() + ', too';
}
}
console.log (Bar.classMethod ());// 'hello' -调用继承的静态方法
console.log(())(新酒吧.classMethod ());// 'Uncaught TypeError' -调用一个实例方法
通过super调用静态方法-这是有效的!
类Foo {
static classMethod() {
返回“你好”;
}
}
类Bar扩展Foo {
static classMethod() {
return super.classMethod() + ', too';
}
}
console.log (Bar.classMethod ());// 'hello, too'
现在,超级上下文基于调用而改变——瞧!
类Foo {
static classMethod() {
返回'hello I am static only';
}
classMethod () {
返回'hello there I am an instance ';
}
}
类Bar扩展Foo {
classMethod () {
return super.classMethod() + ', too';
}
}
console.log(())(新酒吧.classMethod ());// "你好,我也是一个实例"
console.log (Bar.classMethod ());// "你好,我是静态的"
同样,你可以使用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,快乐吧。