Robin's Blog

记录 积累 学习 成长

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

JavaScript类式继承

为了更好的了解JavaScript中类式继承的原理,我们先看一个简单的例子。

  1.     //Super class  
  2.        function Person(){  
  3. this.name='张胜利';  
  4.        this.age=23;  
  5. this.getName = function(){  
  6.     return this.name;  
  7. };  
  8. };  
  9. Person.prototype.getAge = function(){  
  10.     return this.age;  
  11. };  
  12.        //sub class  
  13. function reader(){  
  14. Person.call(this);  
  15. };  
  16. //这句话一定要放到添加的新方法的最前面,否则会把新添加的方法给覆盖掉。  
  17. reader.prototype = new Person();  
  18. reader.prototype.constructor = reader;//由于子类的构造函数被覆盖,所有需要重置构造函数  

 

下面来看具体分解:

  1. 在子类的构造函数中Person.call(this);这就话的作用就是调用父类的构造函数。
  2. reader.prototype = new Person();把父类的一个实例对象赋给子类的prototype对象,这样使得子类能够拥有父类的所有属性和方法。
  3. reader.prototype.constructor=reader;由于子类的构造函数被覆盖,所以需要重置构造函数。

如果使用这种方法声明一个子类,复杂又啰嗦。为了使得声明一个子类变得简单,我们把上面的三步放到一个方法中,如下所示:

  1.  function extend(sub,sup){  
  2.     /* 
  3.  *我们在此使用一个空函数,并将用它创建的一个对象实例插入到原型链中,这样做 
  4.  *可以避免创建超类的新实例,因为1.超类的示例可能会比较大2.超类的构造函数有一些副作用3.或者执行一些需要大量计算的任务 
  5. */  
  6.     var f=function(){};  
  7. f.prototype = sup.prototype;  
  8. sub.prototype = new f();  
  9. sub.prototype.constructor = sub;  
  10.  };  

 

具体说明都在注释中,不再详解。

那么下面我们来看,刚开始的例子中子类如何声明:

  1. function reader(){  
  2. Person.call(this);  
  3. };  
  4. //这句话一定要放到添加的新方法的最前面,否则会把新添加的方法给覆盖掉。  
  5. extend(reader,Person);  

 

ok,现在是不是已经简单很多了,但是我们还发现一个问题,在子类的声明中耦合了父类的类名,为了解耦,下面我们来看看extend方法的一个版本:

  1. function extend(sub,sup){  
  2.   
  3.     var f = function(){};  
  4.     f.prototype = sup.prototype;  
  5.     sub.prototype = new f();  
  6.     sub.prototype.constructor = sub;  
  7.      
  8.      
  9.      
  10.     sub.superclass = sup.prototype;//为子类添加一个superclass属性,然后把sup的prototype对象赋予该属性  
  11.     //确保sup的prototype的constructor属性被正确设置,这在用这个新的superclass属性条用超类的构造函数时很重要  
  12.     if(sup.prototype.constructor == Object.prototype.constructor)  
  13.       sup.prototype.constructor = sup;  
  14.        
  15. }  

 

下面我们来看看这个这样使用该方法,子类是如何声明的:

  1. function reader(){  
  2. reader.superclass.constructor.call(this);  
  3. };  
  4. //这句话一定要放到添加的新方法的最前面,否则会把新添加的方法给覆盖掉。  
  5. extend(reader,Person);  

 

ok,上面就是类式继承的整个过程,是不是很简单?下面来看原型继承:

 

JavaScript 原型继承

   在使用原型式继承时,最好忘掉关于类和实例的一切知识。用基于类的办法创建对象包括两个步骤

   1.用一个类的声明定义对象的结构。

   2.实例化该类为创建一个新对象。用这种方式创建的对象都有一套该类的所有示例属性的副本,每一个示例方法都只存在一 份,但每一个对象都有一个指向它的链接。
   
   
   使用原型继承时,不需要使用类来定义对象的结构,只需直接创建一个字面对象即可。这个对象随后可以被新的对象重用,这得益于原型链查找的工作机制。

 

为了能够更清楚的明白这个原理:

我们也先来看一个例子:

  1. var Person = {  
  2.     defaultName : 'zhangshengli',  
  3.     getName : function(){  
  4.     return this.defaultName;  
  5.     }  
  6. };  
  7. var Reader = create(Person);  
  8. alert(Reader.defaultName);  

 

 

我们看到在上面的例子中,我们用到了一个create函数,通过使用这个create函数,就会生成父类的一个子类,那么这个子类是如何实现的呢???请看下面:

  1.  function create(o) {  
  2.      function F() {};// 首先创建一个新的空函数  
  3.      F.prototype = o;//把F的prototype属性设置为传入的参数o的原型对象,由此可以体会到JavaScript的最初设计者的意图,prototype属性就是用来指向原型对象的,  
  4.      return new F();//最后把new元素符作用于F创建的一个新对象,然后把这个新对象作为返回值返回,函数的所返回的这个克隆结果,是一个以给定对象为原型对象的空对象。  
  5. }  

 

该函数的具体解释,已经在注释中,下面我们来看看该函数的两个变体:

  1.    /*                作为Object的prototyped的一个属性被创建,这样任何对象都可以使用他*/  
  2.    Object.prototype.create= function () {  
  3.     function F() {}  
  4.     F.prototype = this;  
  5.     return new F();  
  6. };  
  7. newObject = oldObject.create();  

 

下面是另一个变体:

  1. if (typeof Object.create !== 'function') {  
  2.     Object.create = function (o) {  
  3.         function F() {}  
  4.         F.prototype = o;  
  5.         return new F();  
  6.     };  
  7. }  
  8. newObject = Object.create(oldObject);  

 

具体不再解释,想必大家肯定都已经明白了,如果不太明白,在好好看看那本犀牛书。

posted on 2009-03-17 16:01  Robin99  阅读(310)  评论(0编辑  收藏  举报