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;//由于子类的构造函数被覆盖,所有需要重置构造函数
下面来看具体分解:
- 在子类的构造函数中Person.call(this);这就话的作用就是调用父类的构造函数。
- reader.prototype = new Person();把父类的一个实例对象赋给子类的prototype对象,这样使得子类能够拥有父类的所有属性和方法。
- 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);
具体不再解释,想必大家肯定都已经明白了,如果不太明白,在好好看看那本犀牛书。