阅读808 返回首页    go 阿里云 go 技术社区[云栖]


javascript 类式继承与原型继承

JavaScript类式继承

为了更好的了解JavaScript中类式继承的原理,我们先看一个简单的例子。 //Super class function Person(){ this.name='张胜利'; this.age=23; this.getName = function(){ return this.name; }; }; Person.prototype.getAge = function(){ return this.age; }; //sub class function reader(){ Person.call(this); }; //这句话一定要放到添加的新方法的最前面,否则会把新添加的方法给覆盖掉。 reader.prototype = new Person(); reader.prototype.constructor = reader;//由于子类的构造函数被覆盖,所有需要重置构造函数

下面来看具体分解:

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

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

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

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

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

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

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

function extend(sub,sup){ var f = function(){}; f.prototype = sup.prototype; sub.prototype = new f(); sub.prototype.constructor = sub; sub.superclass = sup.prototype;//为子类添加一个superclass属性,然后把sup的prototype对象赋予该属性 //确保sup的prototype的constructor属性被正确设置,这在用这个新的superclass属性条用超类的构造函数时很重要 if(sup.prototype.constructor == Object.prototype.constructor) sup.prototype.constructor = sup; }

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

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

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

 

JavaScript 原型继承

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

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

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

 

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

我们也先来看一个例子:

var Person = { defaultName : 'zhangshengli', getName : function(){ return this.defaultName; } }; var Reader = create(Person); alert(Reader.defaultName);

 

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

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

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

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

下面是另一个变体:

if (typeof Object.create !== 'function') { Object.create = function (o) { function F() {} F.prototype = o; return new F(); }; } newObject = Object.create(oldObject);

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

 

上面的文章如果有不妥之处,希望大家多多执政。

最后更新:2017-04-02 00:06:42

  上一篇:go Digester:一个通用xml引擎的设计剖析
  下一篇:go QT的插件机制在程序发布时易出现的问题