ECMAScript 中实现继承的方式不止一种。这是因为 JavaScript 中的继承机制并不是明确规定的,而是通过模仿实现的。这意味着所有的继承细节并非由解释程序处理。
对象冒充--- 构造函数使用 this 关键字给所有属性和方法赋值(即采用类声明的构造函数方式)。因为构造函数只是一个函数,所以可使 ClassA 的构造函数成为 ClassB 的方法,然后调用它。 ClassB 就会收到 ClassA 的构造函数中定义的属性和方法。
所有的新属性和新方法都必须在删除了新方法的代码行后定义。否则,可能会覆盖超类的相关属性和方法.
可以实现多继承
call() 方法--- 与经典的对象冒充方法相似, 第一个参数用作 this 的对象。其他参数都直接传递给函数自身。
Js代码
apply() 方法--- 与call()相似,两个参数,用作 this 的对象和要传递给函数的参数的数组。
原型链--- 用另一类型的对象重写类的 prototype 属性。
prototype 对象的任何属性和方法都被传递给那个类的所有实例。 子类的所有属性和方法都必须出现在 prototype 属性被赋值后,因为在它之前赋值的所有方法都会被删除。
缺点:使用原型链,就无法使用带参构造函数了
混合方式--- 对象冒充继承构造函数的属性,用原型链继承 prototype 对象的方法。
其他继承方式:
zInherit 库( http://www.nczonline.net/downloads ): 支持所有的现代浏览器( Mozilla 、 IE 、 Opera 、 Safari )及一些旧的浏览器( Netscape 4.x 、 IE 、 Mac )。(需要引入 zinherit.js (见附件))
zInherit 库给 Object 类添加了两个方法:
----inheritFrom(): 负责复制指定类的所有方法, 接受一个参数,即要复制的方法所属的类
----instanceOf(): instanceof 运算符的替代品
xbObjects: 为 JavaScript 提供更强的面向对象范型,不止支持继承,还支持方法的重载和调用超类方法的能力。
(xbObjects.js见附件)
几个方法:
--registerClass(className, parentClassName):参数以字符串形式传递,如父类不明确,可以只用第一个参数
--defineClass(className, prototype_func):className为字符串形式的类名,prototype_func为函数指针(函数名)
--parentMethod(method,args...):接受任意多个参数,但第一个参数总是要调用的父类方法的名字(该参数必须是字符串,而不是函数指针),所有其他参数都被传给父类的方法。
---
Js代码
//1,必须注册类
_classes.registerClass("Polygon");
function Polygon(iSides) {
//2,在构造函数内调用defineClass()方法
_classes.defineClass("Polygon", prototypeFunction);
//3,
this.init(iSides);
//该函数用于初始化对象的所有属性和方法
function prototypeFunction() {
Polygon.prototype.init = function(iSides) {
this.parentMethod("init");
this.sides = iSides;
};
Polygon.prototype.getArea = function () {
return 0;
};
}
}
_classes.registerClass("Triangle", "Polygon");
function Triangle(iBase, iHeight) {
_classes.defineClass("Triangle", prototypeFunction);
this.init(iBase,iHeight);
function prototypeFunction() {
Triangle.prototype.init = function(iBase, iHeight) {
this.parentMethod("init", 3);
this.base = iBase;
this.height = iHeight;
};
Triangle.prototype.getArea = function () {
return 0.5 * this.base * this.height;
};
}
}
_classes.registerClass("Rectangle", "Polygon");
function Rectangle(iLength, iWidth) {
_classes.defineClass("Rectangle", prototypeFunction);
this.init(iLength, iWidth);
function prototypeFunction() {
Rectangle.prototype.init = function(iLength, iWidth) {
this.parentMethod("init", 4);
this.length = iLength;
this.width = iWidth;
}
Rectangle.prototype.getArea = function () {
return this.length * this.width;
};
}
}
对象冒充--- 构造函数使用 this 关键字给所有属性和方法赋值(即采用类声明的构造函数方式)。因为构造函数只是一个函数,所以可使 ClassA 的构造函数成为 ClassB 的方法,然后调用它。 ClassB 就会收到 ClassA 的构造函数中定义的属性和方法。
- Js代码
- function ClassA(sColor){
- this.color = sColor;
- this.sayColor = function (){
- alert(this.color);
- }
- }
- function ClassB(sColor,sName){
- this.newMethod = ClassA; //为ClassA赋予了方法newMethod
- this.newMethod(sColor); //调用newMethod
- delete this.newMethod; //删除对ClassA的引用
- this.name = sName;
- this.sayName = function(){
- alert(this.name);
- }
- }
- <span style="font-size:16px;">Js代码
- function ClassA(sColor){
- this.color = sColor;
- this.sayColor = function (){
- alert(this.color);
- }
- }
- function ClassB(sColor,sName){
- this.newMethod = ClassA; //为ClassA赋予了方法newMethod
- this.newMethod(sColor); //调用newMethod
- delete this.newMethod; //删除对ClassA的引用
- this.name = sName;
- this.sayName = function(){
- alert(this.name);
- }
- }
- </span>
- function ClassA(sColor){
- this.color = sColor;
- this.sayColor = function (){
- alert(this.color);
- }
- }
- function ClassB(sColor,sName){
- this.newMethod = ClassA; //为ClassA赋予了方法newMethod
- this.newMethod(sColor); //调用newMethod
- delete this.newMethod; //删除对ClassA的引用
- this.name = sName;
- this.sayName = function(){
- alert(this.name);
- }
- }
- <span style="font-size:16px;">function ClassA(sColor){
- this.color = sColor;
- this.sayColor = function (){
- alert(this.color);
- }
- }
- function ClassB(sColor,sName){
- this.newMethod = ClassA; //为ClassA赋予了方法newMethod
- this.newMethod(sColor); //调用newMethod
- delete this.newMethod; //删除对ClassA的引用
- this.name = sName;
- this.sayName = function(){
- alert(this.name);
- }
- } </span>
所有的新属性和新方法都必须在删除了新方法的代码行后定义。否则,可能会覆盖超类的相关属性和方法.
可以实现多继承
call() 方法--- 与经典的对象冒充方法相似, 第一个参数用作 this 的对象。其他参数都直接传递给函数自身。
Js代码
- function ClassA(sColor){
- this.color = sColor;
- this.sayColor = function (){
- alert(this.color);
- }
- }
- function ClassB(sColor,sName){
- ClassA.call(this,sColor); //this让ClassA中的关键字this等于新创建的ClassB对象
- //第二个参数sColor对两个类来说都是唯一的参数。
- this.name = sName;
- this.sayName = function(){
- alert(this.name);
- }
- }
- function ClassA(sColor){
- this.color = sColor;
- this.sayColor = function (){
- alert(this.color);
- }
- }
- function ClassB(sColor,sName){
- ClassA.call(this,sColor); //this让ClassA中的关键字this等于新创建的ClassB对象
- //第二个参数sColor对两个类来说都是唯一的参数。
- this.name = sName;
- this.sayName = function(){
- alert(this.name);
- }
- }
- <span style="font-size:16px;">function ClassA(sColor){
- this.color = sColor;
- this.sayColor = function (){
- alert(this.color);
- }
- }
- function ClassB(sColor,sName){
- ClassA.call(this,sColor); //this让ClassA中的关键字this等于新创建的ClassB对象
- //第二个参数sColor对两个类来说都是唯一的参数。
- this.name = sName;
- this.sayName = function(){
- alert(this.name);
- }
- }
- function ClassA(sColor){
- this.color = sColor;
- this.sayColor = function (){
- alert(this.color);
- }
- }
- function ClassB(sColor,sName){
- ClassA.call(this,sColor); //this让ClassA中的关键字this等于新创建的ClassB对象
- //第二个参数sColor对两个类来说都是唯一的参数。
- this.name = sName;
- this.sayName = function(){
- alert(this.name);
- }
- } </span>
apply() 方法--- 与call()相似,两个参数,用作 this 的对象和要传递给函数的参数的数组。
- Js代码
- function ClassA(sColor){
- this.color = sColor;
- this.sayColor = function (){
- alert(this.color);
- }
- }
- function ClassB(sColor,sName){
- ClassA.apply(this,arguments);//只有超类中的参数顺序与子类中的参数顺序完全一致时才可以传递参数对象
- ClassA.apply(this,new Array(sColor));//如果不是,就必须创建一个单独的数组,按照正确的顺序放置参数。
- this.name = sName;
- this.sayName = function(){
- alert(this.name);
- }
- }
- function ClassA(sColor){
- this.color = sColor;
- this.sayColor = function (){
- alert(this.color);
- }
- }
- function ClassB(sColor,sName){
- ClassA.apply(this,arguments);//只有超类中的参数顺序与子类中的参数顺序完全一致时才可以传递参数对象
- ClassA.apply(this,new Array(sColor));//如果不是,就必须创建一个单独的数组,按照正确的顺序放置参数。
- this.name = sName;
- this.sayName = function(){
- alert(this.name);
- }
- }
- <span style="font-size:16px;">Js代码
- function ClassA(sColor){
- this.color = sColor;
- this.sayColor = function (){
- alert(this.color);
- }
- }
- function ClassB(sColor,sName){
- ClassA.apply(this,arguments);//只有超类中的参数顺序与子类中的参数顺序完全一致时才可以传递参数对象
- ClassA.apply(this,new Array(sColor));//如果不是,就必须创建一个单独的数组,按照正确的顺序放置参数。
- this.name = sName;
- this.sayName = function(){
- alert(this.name);
- }
- }
- function ClassA(sColor){
- this.color = sColor;
- this.sayColor = function (){
- alert(this.color);
- }
- }
- function ClassB(sColor,sName){
- ClassA.apply(this,arguments);//只有超类中的参数顺序与子类中的参数顺序完全一致时才可以传递参数对象
- ClassA.apply(this,new Array(sColor));//如果不是,就必须创建一个单独的数组,按照正确的顺序放置参数。
- this.name = sName;
- this.sayName = function(){
- alert(this.name);
- }
- } </span>
原型链--- 用另一类型的对象重写类的 prototype 属性。
prototype 对象的任何属性和方法都被传递给那个类的所有实例。 子类的所有属性和方法都必须出现在 prototype 属性被赋值后,因为在它之前赋值的所有方法都会被删除。
缺点:使用原型链,就无法使用带参构造函数了
- Js代码
- function ClassA(){
- }
- ClassA.prototype.name = "nomad";
- ClassA.prototype.sayName = function(){
- alert(this.name);
- }
- function ClassB()
- }
- ClassB.prototype = new ClassA(); //要确保调用构造函数没有任何参数。
- ClassB.prototype.age = 23;
- ClassB.prototype.sayAge = function(){
- alert(this.age);
- }
- function ClassA(){
- }
- ClassA.prototype.name = "nomad";
- ClassA.prototype.sayName = function(){
- alert(this.name);
- }
- function ClassB()
- }
- ClassB.prototype = new ClassA(); //要确保调用构造函数没有任何参数。
- ClassB.prototype.age = 23;
- ClassB.prototype.sayAge = function(){
- alert(this.age);
- }
- <span style="font-size:16px;">Js代码
- function ClassA(){
- }
- ClassA.prototype.name = "nomad";
- ClassA.prototype.sayName = function(){
- alert(this.name);
- }
- function ClassB()
- }
- ClassB.prototype = new ClassA(); //要确保调用构造函数没有任何参数。
- ClassB.prototype.age = 23;
- ClassB.prototype.sayAge = function(){
- alert(this.age);
- }
- function ClassA(){
- }
- ClassA.prototype.name = "nomad";
- ClassA.prototype.sayName = function(){
- alert(this.name);
- }
- function ClassB()
- }
- ClassB.prototype = new ClassA(); //要确保调用构造函数没有任何参数。
- ClassB.prototype.age = 23;
- ClassB.prototype.sayAge = function(){
- alert(this.age);
- } </span>
混合方式--- 对象冒充继承构造函数的属性,用原型链继承 prototype 对象的方法。
- Js代码
- function ClassA(aName){
- this.name = aName;
- }
- ClassA.prototype.sayName = function(){
- alert(this.name);
- }
- function ClassB(aName,aAge){
- ClassA.call(this,aName);
- }
- ClassB.prototype = new ClassA();
- ClassB.prototype.sayAge = function(){
- alert(this.age);
- }
- function ClassA(aName){
- this.name = aName;
- }
- ClassA.prototype.sayName = function(){
- alert(this.name);
- }
- function ClassB(aName,aAge){
- ClassA.call(this,aName);
- }
- ClassB.prototype = new ClassA();
- ClassB.prototype.sayAge = function(){
- alert(this.age);
- }
- <span style="font-size:16px;">Js代码
- function ClassA(aName){
- this.name = aName;
- }
- ClassA.prototype.sayName = function(){
- alert(this.name);
- }
- function ClassB(aName,aAge){
- ClassA.call(this,aName);
- }
- ClassB.prototype = new ClassA();
- ClassB.prototype.sayAge = function(){
- alert(this.age);
- }
- function ClassA(aName){
- this.name = aName;
- }
- ClassA.prototype.sayName = function(){
- alert(this.name);
- }
- function ClassB(aName,aAge){
- ClassA.call(this,aName);
- }
- ClassB.prototype = new ClassA();
- ClassB.prototype.sayAge = function(){
- alert(this.age);
- } </span>
zInherit 库( http://www.nczonline.net/downloads ): 支持所有的现代浏览器( Mozilla 、 IE 、 Opera 、 Safari )及一些旧的浏览器( Netscape 4.x 、 IE 、 Mac )。(需要引入 zinherit.js (见附件))
zInherit 库给 Object 类添加了两个方法:
----inheritFrom(): 负责复制指定类的所有方法, 接受一个参数,即要复制的方法所属的类
----instanceOf(): instanceof 运算符的替代品
- Js代码
- <script type="text/javascript" src="~/zinherit.js"></script>
- function ClassA(){
- }
- ClassA.prototype.name = "nomad";
- ClassA.prototype.sayName = function(){
- alert(this.name);
- }
- function ClassB(){
- }
- ClassB.prototype.inheritFrom(ClassA);
- ClassB.prototype.age = 23;
- ClassB.prototype.sayAge = function(){
- alert(this.age);
- }
- <script type="text/javascript" src="~/zinherit.js"></script>
- function ClassA(){
- }
- ClassA.prototype.name = "nomad";
- ClassA.prototype.sayName = function(){
- alert(this.name);
- }
- function ClassB(){
- }
- ClassB.prototype.inheritFrom(ClassA);
- ClassB.prototype.age = 23;
- ClassB.prototype.sayAge = function(){
- alert(this.age);
- }
- <span style="font-size:16px;">Js代码
- <script type="text/javascript" src="~/zinherit.js"></script>
- function ClassA(){
- }
- ClassA.prototype.name = "nomad";
- ClassA.prototype.sayName = function(){
- alert(this.name);
- }
- function ClassB(){
- }
- ClassB.prototype.inheritFrom(ClassA);
- ClassB.prototype.age = 23;
- ClassB.prototype.sayAge = function(){
- alert(this.age);
- }
- <script type="text/javascript" src="~/zinherit.js"></script>
- function ClassA(){
- }
- ClassA.prototype.name = "nomad";
- ClassA.prototype.sayName = function(){
- alert(this.name);
- }
- function ClassB(){
- }
- ClassB.prototype.inheritFrom(ClassA);
- ClassB.prototype.age = 23;
- ClassB.prototype.sayAge = function(){
- alert(this.age);
- } </span>
xbObjects: 为 JavaScript 提供更强的面向对象范型,不止支持继承,还支持方法的重载和调用超类方法的能力。
(xbObjects.js见附件)
几个方法:
--registerClass(className, parentClassName):参数以字符串形式传递,如父类不明确,可以只用第一个参数
--defineClass(className, prototype_func):className为字符串形式的类名,prototype_func为函数指针(函数名)
--parentMethod(method,args...):接受任意多个参数,但第一个参数总是要调用的父类方法的名字(该参数必须是字符串,而不是函数指针),所有其他参数都被传给父类的方法。
---
Js代码
//1,必须注册类
_classes.registerClass("Polygon");
function Polygon(iSides) {
//2,在构造函数内调用defineClass()方法
_classes.defineClass("Polygon", prototypeFunction);
//3,
this.init(iSides);
//该函数用于初始化对象的所有属性和方法
function prototypeFunction() {
Polygon.prototype.init = function(iSides) {
this.parentMethod("init");
this.sides = iSides;
};
Polygon.prototype.getArea = function () {
return 0;
};
}
}
_classes.registerClass("Triangle", "Polygon");
function Triangle(iBase, iHeight) {
_classes.defineClass("Triangle", prototypeFunction);
this.init(iBase,iHeight);
function prototypeFunction() {
Triangle.prototype.init = function(iBase, iHeight) {
this.parentMethod("init", 3);
this.base = iBase;
this.height = iHeight;
};
Triangle.prototype.getArea = function () {
return 0.5 * this.base * this.height;
};
}
}
_classes.registerClass("Rectangle", "Polygon");
function Rectangle(iLength, iWidth) {
_classes.defineClass("Rectangle", prototypeFunction);
this.init(iLength, iWidth);
function prototypeFunction() {
Rectangle.prototype.init = function(iLength, iWidth) {
this.parentMethod("init", 4);
this.length = iLength;
this.width = iWidth;
}
Rectangle.prototype.getArea = function () {
return this.length * this.width;
};
}
}