2016-07-07 53 views
1

与面向类的语言相比,JS基于原型,而对象的构造函数不仅包含“构造函数逻辑”(我在MDN中发现了这个术语),而且构造函数还定义了特权方法。在一个“类”是另一个类的孩子的情况下(遗憾的是,我不知道比JS的“类”更好的术语),这导致父类构造函数在子类能够覆盖之前执行的问题一个方法或者子类不能重写一个方法,因为构造函数还没有运行。Javascript:如何在覆盖子类中的继承方法之后运行父类的构造函数逻辑?

我会举一个例子来说明我的意思。假定在对象上定义了特权函数的“父类”以及调用此方法的构造函数逻辑。

function Parent() { 
    this.methodA = function() { 
    // do something 
    }; 

    // C'tor logic starts here 
    // Beside other things also call some method of this object 
    this.methodA(); 
} 

假设一个孩子的类,应重新定义methodA但仍使用父类的构造函数 逻辑。

第一种方法是在 子构造函数的开头调用父构造函数。但是,父构造函数仍然调用父项的实现。

Child.prototype = Object.create(Parent.prototype); 
Child.prototype.constructor = Child; 

function Child() { 
    // Call parent constructor first. Problem: The parent constructor 
    // calls methodA before it will be overriden by child constructor 
    Parent.call(this); 

    var _oldMethodA = this.methodA; 
    this.methodA = function() { 
    // do something special and then call parent method 
    _oldMethodA.call(this); 
    }; 
} 

第二种方法是以后调用父构造,但是,然后 父方法不能被重写。

Child.prototype = Object.create(Parent.prototype); 
Child.prototype.constructor = Child; 

function Child() { 
    // Override first. Problem: The parent constructor has not defined methodA 
    // yet, hence the line below fails. 
    var _oldMethodA = this.methodA; 
    this.methodA = function() { 
    // do something special and call parent method 
    _oldMethodA.call(this); 
    }; 

    Parent.call(this); 
} 

如何交叉JS构造函数的两个任务 - 特权方法和构造函数逻辑的定义 - 按正确的顺序调用?

附录 - 附加材料,由于意见

我从评论想通了,它似乎并没有被清楚我想要什么。因此,这里是用Java编写的

class Parent { 
    public Parent() { 
    methodA(); 
    } 

    public void methodA() { 
    System.out.println("I do the work of the parent's method"); 
    } 
} 

class Child extends Parent { 
    public Child { 
    super(); 
    } 

    public void methodA() { 
    System.out.println("I do the work of the child's method and ..."); 
    super(); 
    } 
} 

Parent p = new Parent(); 
Child c = new Child(); 

的例子这将导致下面的输出

$> I do the work of the parent's method 
$> I do the work of the child's method and ... 
$> I do the work of the parent's method 

这是什么情况。 Parent的构造函数调用Parent中定义的methodA的实现。这没什么特别的,并产生第一行输出。 Child的构造函数只是调用父类的构造函数,它再次像以前那样调用methodA。但是,尽管这是父级的构造函数,但该对象仍然是Child的一个实例,因此将执行子级的methodA的实现。此方法打印输出的第二行,然后显式调用生成第三行的父级方法。

根据OOP,这是完美的正确行为,这也是我想用Javascript实现的。所以它实际上是opposite of the problem mentioned here。链接来自评论。

+0

哪里是'methodB'? – Ben

+0

您的问题不是基于原型的继承或特权方法,而是从构造函数中调用可覆盖的方法。这在我见过的任何语言中都不太好。 – Bergi

+0

@BenAston:对不起,'methodB'是评论中的一个错字。该示例的以前版本使用了两种方法,但我将MWE简化为一种方法。 – user2690527

回答

-1

真的不知道你怎么想在这里实现,但总体来讲,你可以做这样的事情:

function Parent() { 
    if (this.methodA == null) { 
    this.methodA = function() { 
     // do something 
     console.log('parent'); 
    }; 
    } 

    // C'tor logic starts here 
    // Beside other things also call some method of this object 
    this.methodA(); 
} 

function Child() { 

    this.methodA = (function(_oldMethodA) { 
    return function() { 
     console.log('child'); 
     // do something special and then call parent method 
     if (_oldMethodA) { 
     _oldMethodA.call(this); 
     } 
    } 
    })(this.methodA); 

    Parent.call(this); 
} 

Child.prototype = Object.create(Parent.prototype); 
Child.prototype.constructor = Child; 

new Child(); // yields: 'child' 

但判断上,你想做的事,你可能要添加一些数组中的父母,发生了什么是你在父类中重写你的方法A

+0

在你的'孩子'中,'_oldMethodA'总是'未定义' – Bergi

+0

不,这个“解决方案”没有任何意义。正如Bergi所说,'_oldMethodA'总是未定义的,因为它是一个未命名函数的参数,它以'this.methodA'作为参数被调用,但'this.methodA'仍有待定义。此代码显示某种“自我指涉”。 – user2690527

0

在调用父类之前,可以将该属性定义为子类中的一个访问器。

这样,您将能够获得对父类指定的函数的引用,但仍可在getter中提供所需的函数。

function Parent() { 
 
    this.methodA = function() { console.log('Parent method'); }; 
 
    this.methodA(); 
 
} 
 
function Child() { 
 
    var _oldMethodA; 
 
    var _newMethodA = function() { 
 
    console.log('Code injected by Child'); 
 
    _oldMethodA.call(this); 
 
    }; 
 
    Object.defineProperty(this, 'methodA', { 
 
    configurable: true, 
 
    enumerable: true, 
 
    set: function(val){ _oldMethodA = val; }, 
 
    get: function(){ return _newMethodA; } 
 
    }); 
 
    Parent.call(this); 
 
    /* Optional: convert it back to a data property */ 
 
    Object.defineProperty(this, 'methodA', { 
 
    value: _newMethodA, 
 
    writable: true 
 
    }); 
 
} 
 
Child.prototype = Object.create(Parent.prototype); 
 
Child.prototype.constructor = Child; 
 
new Child();

+0

Urgh。我很高兴这不再在ES6中工作:-) – Bergi

+0

@Bergi是的,这是丑陋的代码。但我认为它应该仍然在ES6中工作,不是吗? – Oriol

+0

它似乎在做我想达到的目标,我尊重想到这个解决方案所需的创造力。但它太复杂了,我不想使用它。对不起;-)代码必须清晰准确。这实际上看起来像有人试图手动执行代码混淆;-) – user2690527