6)类的继承
1)利用共享prototype原型对象实现继承.
继承是面向对象开发的一个重要概念.在JavaScript中没有专门的机制来实现类的继承,但可以通过拷贝一个类的prototype到另外一个类实现继承.一种简单的继承实现如下:
JavaScript提供了instanceof操作符来判断一个对象是否是某个类的实例,对于上面创建的obj对象,下面两条语句都是成立的:
这里弹出了两次对话框"2",可见,当对class2进行prototype的改变时,class1的prototype也随之改变,即使对class2 的prototype增减一些成员,class1的成员也随之改变.这里的奥秘是:class1和class2的prototype是完全相同的,是对同一个对象的引用.
在JavaScript中,除了基本的数据类型(数字\字符串\布尔等),所有的赋值以及函数参数都是引用传递,而不是值传递.(这与C#类似,也是JavaScript提高性能的一个手段.)
上面的 class2.prototype=class1.prototype; 语句,仅仅是让class2的prototype对象引用class1的prototype,造成了基类与子类的成员定义始终保持一致的效果.
从这里也看到了instanceof操作符的执行机制,它就是判断一个对象是否是一个prototype的实例,因为这里的obj1和obj2都是对应于同一个prototype,所以它们instanceof的结果都是相同的。
因此,使用prototype引用拷贝实现继承不是正确的方法.下面,利用反射机制和prototype来实现正确的类继承.
2)利用反射机制和prototype实现继承.
利用反射机制实现类的继承,思路如下:利用for(...in...)语句遍历出所有基类的prototype的成员,并将其赋值给子类的prototype对象,例如:
为了方便开发,可以为每个类添加一个共有的方法,用以实现类的继承:
3)prototype.js框架中的类继承实现机制.
在prototype.js框架中,首先为所有的对象定义一个extend方法:
Object.extend方法很容易理解,它是Object类的一个静态方法(只能用"类名.方法名"的形式调用),用于将参数中source的所有属性都赋值到destination对象中,并返回destination对象.
而Object.prototype.extend,因为Object是所有对象的基类,因此这里是为所有对象添加一个extend方法,出于代码复用的角度,使用了如下语句:
Object.extend.apply(this,[this,object]);
这一句是将Object类的静态方法作为对象的方法运行,第一个参数this是指向对象实例自身(这里无所谓);第二个参数是一个数组,包括两个元素:对象本身和传进来的对象参数object.
如下类继承实现:
继承是面向对象开发的一个重要概念.在JavaScript中没有专门的机制来实现类的继承,但可以通过拷贝一个类的prototype到另外一个类实现继承.一种简单的继承实现如下:
fucntion class1(){
//构造函数
}
function class2(){
//构造函数
}
class2.prototype=class1.prototype;
class2.prototype.moreProperty1="xxx";
class2.prototype.moreMethod1=function(){
//方法实现代码
}
var obj=new class2();
这样,首先是class2具有了class1一样的prototype,不考虑构造函数,两个类是等价的.随后,又通过prototype给class2
赋予了两个额外的方法,所以class2是在class1的基础上增加了属性和方法,这就实现了类的继承.//构造函数
}
function class2(){
//构造函数
}
class2.prototype=class1.prototype;
class2.prototype.moreProperty1="xxx";
class2.prototype.moreMethod1=function(){
//方法实现代码
}
var obj=new class2();
JavaScript提供了instanceof操作符来判断一个对象是否是某个类的实例,对于上面创建的obj对象,下面两条语句都是成立的:
obj instanceof class1
obj instanceof class2
表面上看,上面的实现完全可行,JavaScript也能正确理解这种继承关系,obj同时是class1和class2的实例.但是事实上是不对的,JavaScript的这种理解实际上是基于一种很简单的策略,如下,先使用prototype让class2继承于class1,再在class2中重复定义method方法:obj instanceof class2
//定义class1
function class1(){
//构造函数
}
//定义class1的成员
class1.prototype={
m1:function(){
alert(1);
}
}
//定义class2
function class2(){
//构造函数
}
//让class2继承于class1
class2.prototype=class1.prototype;
//给class2重复定义方法method
class2.prototype.method=function(){
alert(2);
}
//创建两个类的实例
var obj1=new class1();
var obj2=new class2();
//分别调用两个对象的method方法
obj1.method();
obj2.method();
(明白了,这里用prototype等于基类的prototype来实现,在改变子类的prototype属性(方法)的时候,会影响到基类的属性(方
法),这显然大大不对啦.解决的方法,应该是拷贝基类的prototype属性,而不应该是赋予.)function class1(){
//构造函数
}
//定义class1的成员
class1.prototype={
m1:function(){
alert(1);
}
}
//定义class2
function class2(){
//构造函数
}
//让class2继承于class1
class2.prototype=class1.prototype;
//给class2重复定义方法method
class2.prototype.method=function(){
alert(2);
}
//创建两个类的实例
var obj1=new class1();
var obj2=new class2();
//分别调用两个对象的method方法
obj1.method();
obj2.method();
这里弹出了两次对话框"2",可见,当对class2进行prototype的改变时,class1的prototype也随之改变,即使对class2 的prototype增减一些成员,class1的成员也随之改变.这里的奥秘是:class1和class2的prototype是完全相同的,是对同一个对象的引用.
在JavaScript中,除了基本的数据类型(数字\字符串\布尔等),所有的赋值以及函数参数都是引用传递,而不是值传递.(这与C#类似,也是JavaScript提高性能的一个手段.)
上面的 class2.prototype=class1.prototype; 语句,仅仅是让class2的prototype对象引用class1的prototype,造成了基类与子类的成员定义始终保持一致的效果.
从这里也看到了instanceof操作符的执行机制,它就是判断一个对象是否是一个prototype的实例,因为这里的obj1和obj2都是对应于同一个prototype,所以它们instanceof的结果都是相同的。
因此,使用prototype引用拷贝实现继承不是正确的方法.下面,利用反射机制和prototype来实现正确的类继承.
2)利用反射机制和prototype实现继承.
利用反射机制实现类的继承,思路如下:利用for(...in...)语句遍历出所有基类的prototype的成员,并将其赋值给子类的prototype对象,例如:
//class1
function class1(){
//构造函数
}
class1.prototype={
method:function(){
alert(1);
},
method2:function(){
alert("method2");
}
}
//class2
function class2(){
//构造函数
}
//让class2继承于class1
for(var p in class1.prototype){ //遍历class1.prototype的属性和方法
if (class2.prototype[p] == null) //如果类class2中没有此属性或方法,则进行拷贝
class2.prototype[p]=class1.prototype[p];
}
//覆盖定义class1中的method方法
class2.prototype.method=function(){
alert(2);
}
//创建两个类的实例
var obj1=new class1();
var obj2=new class2();
//分别调用obj1和obj2的method方法
obj1.method();
obj2.method();
//分别调用obj1和obj2的method2方法
obj1.method2();
obj2.method2();
从运行结果可见,obj2中重复定义的method已经覆盖了继承的method方法,同时method2方法未受影响。而且obj1中的method方法仍然保持了原有的定义。这样,就实现了正确意义的类的继承.function class1(){
//构造函数
}
class1.prototype={
method:function(){
alert(1);
},
method2:function(){
alert("method2");
}
}
//class2
function class2(){
//构造函数
}
//让class2继承于class1
for(var p in class1.prototype){ //遍历class1.prototype的属性和方法
if (class2.prototype[p] == null) //如果类class2中没有此属性或方法,则进行拷贝
class2.prototype[p]=class1.prototype[p];
}
//覆盖定义class1中的method方法
class2.prototype.method=function(){
alert(2);
}
//创建两个类的实例
var obj1=new class1();
var obj2=new class2();
//分别调用obj1和obj2的method方法
obj1.method();
obj2.method();
//分别调用obj1和obj2的method2方法
obj1.method2();
obj2.method2();
为了方便开发,可以为每个类添加一个共有的方法,用以实现类的继承:
Function.prototype.inherit = function(baseClass){
for (var p in baseClass.prototype){
if (this.prototype[p] == null){
this.prototype[p] = baseClass.prototype[p];
}
}
}
这里使用所有函数对象(类)的共同类Function来添加继承方法,这样所有的类都会有一个inherit方法,用以实现基于prototype的继承.for (var p in baseClass.prototype){
if (this.prototype[p] == null){
this.prototype[p] = baseClass.prototype[p];
}
}
}
3)prototype.js框架中的类继承实现机制.
在prototype.js框架中,首先为所有的对象定义一个extend方法:
Object.extend方法很容易理解,它是Object类的一个静态方法(只能用"类名.方法名"的形式调用),用于将参数中source的所有属性都赋值到destination对象中,并返回destination对象.
而Object.prototype.extend,因为Object是所有对象的基类,因此这里是为所有对象添加一个extend方法,出于代码复用的角度,使用了如下语句:
Object.extend.apply(this,[this,object]);
这一句是将Object类的静态方法作为对象的方法运行,第一个参数this是指向对象实例自身(这里无所谓);第二个参数是一个数组,包括两个元素:对象本身和传进来的对象参数object.
如下类继承实现:
//为Object类添加静态方法:extend
Object.extend = function(destination, source) {
for(property in source) {
if (destination[property] == null){
destination[property] = source[property];
}
}
return destination;
}
//class1
function class1(){
//构造函数
}
class1.prototype={
age:"sss",
method:function(){
alert(1);
},
method2:function(){
alert("method2");
}
}
class1.show = function(){
alert("class1的静态方法");
}
//class2
function class2(){
//构造函数
}
//覆盖定义class1中的method方法
class2.prototype.method=function(){
alert(2);
}
//Object.extend时,子类与父类必须一致.
Object.extend(class2.prototype,class1.prototype); //继承常规属性和方法
Object.extend(class2,class1); //继承静态属性和方法
//创建两个类的实例
var obj1=new class1();
var obj2=new class2();
//分别调用obj1和obj2的method方法
obj1.method();
obj2.method();
//分别调用obj1和obj2的method2方法
obj1.method2();
obj2.method2();
class2.show();
Object.extend = function(destination, source) {
for(property in source) {
if (destination[property] == null){
destination[property] = source[property];
}
}
return destination;
}
//class1
function class1(){
//构造函数
}
class1.prototype={
age:"sss",
method:function(){
alert(1);
},
method2:function(){
alert("method2");
}
}
class1.show = function(){
alert("class1的静态方法");
}
//class2
function class2(){
//构造函数
}
//覆盖定义class1中的method方法
class2.prototype.method=function(){
alert(2);
}
//Object.extend时,子类与父类必须一致.
Object.extend(class2.prototype,class1.prototype); //继承常规属性和方法
Object.extend(class2,class1); //继承静态属性和方法
//创建两个类的实例
var obj1=new class1();
var obj2=new class2();
//分别调用obj1和obj2的method方法
obj1.method();
obj2.method();
//分别调用obj1和obj2的method2方法
obj1.method2();
obj2.method2();
class2.show();