我想在JS中实现以下行为。 请注意,语法是符号。
这是我的父类
class = TList {
FList: array;
function AddElement(Ele) {
Flist.Add(Ele)
};
function RemoveEle(Ele) {
FList.Remove(Ele)
};
}
现在我要继承这个班级。我的子类应该自动拥有父类的所有属性,并且应该能够扩展它们而不需要重写代码。
class = TAlertList(inherit from TList) {
function AddElement(Ele) {
Alert('element will be added');
call.parent.AddElement(Ele)
};
function RemoveElement(Ele) {
call.parent.RemoveElement(Ele);
Alert('element removed');
}
}
请注意我如何在我希望的地方继承父方法。
现在我应该可以从我的子类创建一个对象并执行以下操作。
MyAlertList = new TAlertList;
MyAlertList.Add('hello');
console.log(MyAlertList.FList);
我应该能够从TAlertList继承更多子类,并能够更改现有行为。我需要在纯ES5中执行此操作而不使用任何库。预计会有标准的OOP实践。
答案 0 :(得分:1)
您的代码如下
function TList(){
this.FList = [];
}
TList.prototype.AddElement = function(Ele){
this.FList.push(Ele);
}
TList.prototype.RemoveElement = function(Ele){
this.FList.splice(Ele,1); //Ele is the index to remove;
}
这是了解继承在JavaScript中如何工作的近似值。
function TAlertList (){
TList.call(this);
}
TAlertList.prototype = Object.create(TList.prototype);
TAlertList.prototype.constructor = TAlertList;
TAlertList.prototype.AddElement = function(ele){
alert('Element will be added');
TList.prototype.AddElement.call(this,ele);
};
TAlertList.prototype.RemoveElement = function(ele){
alert('Element will be remove');
TList.prototype.RemoveElement.call(this,ele);
};
所以,经典的超级电话是
ParentClass.prototype.myMethod.call(this,args);
答案 1 :(得分:0)
这是Q& A
编辑 - 如果您打算阅读全文,请不要忘记阅读@ paul的评论。
几乎所有答案都是基于受欢迎的#34; Person"关于JS OOP的MDN文档中的示例。
此方法背后的理论是将对象的 fields 放在构造函数中,同时在原型对象中实现方法。子对象可以通过使用设计的this
值调用构造函数来继承所有字段。此外,它还可以继承所有方法,方法是将父对象的原型对象与原型对象相同。唯一的规则是,在实现继承时,需要使用call
或apply
调用方法将方法指向正确的this
对象。
我不喜欢这种方法有两个原因。
对象的字段和方法必须在两个对象之间分开(字段 - 构造函数,方法 - 原型)。这并不具有独特实体的独特行为的风格 - 应该是单个类。
继承时必须指定父对象的名称。这不是自动的。让我们说对象 C 继承自对象 A 。因此,在对象 C 的方法中,您需要在继承对象 A 时提及它。 (TList.prototype.AddElement.call(this, Ele);
)如果对象 B 稍后出现怎么办?您必须将 C 的所有继承方法更改为从 B 进行调用。这绝不是接近良好的继承。
我想在MDN方法中克服这些问题。我提出了以下模型,没有this
没有call
而没有apply
。代码简单易懂。在继承父对象时,您不必提及父对象的名称。因此,一个新的课程可以随时进入父母和孩子之间,而不需要太多的改变。请讨论这个,并指出这个模型的弱点。
这是返回父对象的函数。
function tList() {
var ret = Object.create(null);
ret.list = [];
ret.addElement = fucntion(ele) {
ret.list.push(ele)
};
return ret;
}
//You can create tList object like this:
var myList = tList();
myList.addElement('foo');
现在出现了子对象:
function tAlertList() {
var ret = Object.create(tList());
//Lets inherit with the fashion of overriding a virtual method
ret.addElement = function(ele) {
//Here is new code
alert('Adding element ' + ele);
//Automatic inheritance now
Object.getPrototypeOf(ret).addElement(ele);
}
return ret;
}
//Just create the child object and use it
var myAlertList = tAlertList();
myAlertList.addElement('buzz') ;
你可以让大孩子对象并从父母继承而不提及他们的名字。我们假设您必须将tCustomList
放在tList
和tAlertList
之间。您所要做的就是告诉tAlertList
在一个地方继承tCustomList
。 (var ret = Object.create(tCustomList());
)其他一切都保持不变。
这是fiddle。
答案 2 :(得分:-1)
使用纯ES5,您可以这样做:
function TList() {
this.FList = []; //not really ideal.
}
TList.prototype.addElement = function(ele) {
this.FList.push(ele);
};
TList.prototype.removeElement = function(ele) {
this.FList.splice(this.FList.indexOf(ele), 1);
}
function TAlertList(){
this.FList = [];
}
TAlertList.prototype = new TList(); //inherit from TList
TAlertList.prototype.constructor = TAlertList; //reset constructor
TAlertList.prototype.addElement = function(ele) {
alert('element will be added');
TList.prototype.addElement.call(this, ele);
};
TAlertList.prototype.removeElement = function(ele) {
alert('element removed');
TList.prototype.removeElement.call(this, ele);
};
几个笔记:
除非被覆盖,否则其父级的FList
属性实际上将在从父级继承的所有对象之间共享。这意味着如果你不覆盖FList
,你就会得到这个:
var a = new TAlertList();
var b = new TAlertList();
a.push(1); //b.Flist === [1]
在我看来,最好将你的孩子的名字命名为与父母不同的其他名字。这样你就不需要这样做了:
TList.prototype.function.call(this, parameter1, parameter2, ..);
你可以像这样打电话给他们:
this.function(paremeter1, parameter2);
当然,它不是一种静态的方式来调用父级,因为你可以用你自己的方式覆盖这个函数。然后再次TList.prototype.function
不需要拥有该函数的对象的父级的功能。为此,您需要使用非标准的ES5 __proto__
属性。
this.__proto__.function.call(this, parameter1, parameter2, ..);
除非你打算在不同的物体周围使用这个功能,否则你不需要它。