第八章 面向对象之三:继承的原理

      javaScript的继承是通过原型链来实现的,而原型链是各级函数的原型对象的__proto__属性组成的。

      我们知道当一个函数实例化之后,实例对象具有的内容是函数的属性和方法以及一个__proto__,它指向函数的原型对象,从而也具备了原型对象的属性和方法。

      我们如果有如下函数(采自高级程序设计三):

function SuperType () {

    this.property = true;

}

 

SuperType.prototype.getSuperValue = function () {

    return this.property;

};

 

当我们实例化它之后获得一个s,var s = new SuperType();  这个s的内存里实际保存这如下内容:

 

S的内存展示

property:true

__proto__:SuperType的原型对象的引用

 

 

 

 

 

 

我们也可以调用原型里的getSuperValue()方法,但是这个方法是保存在函数原型里的,是js帮我们寻找并调用到的,并不是保存在了s的内存地址里。

然后我们又创建另一个函数:SubType,代码如下:

 

function SubType() {

    this.subproperty = false;

}

 

这时候,这两个函数是没有什么关系的,我们表示如下:

 

 

      我们想让SubType(父类)继承于SuperType(父父类),并且通过父类实例化的对象可以有父类以及父父类的所有属性和方法,如何实现?

      我们知道实例化的对象有它父类的所有属性和方法,还有一个指向父类原型对象的__proto__属性,使得我们还可以调用父类的原型的属性和方法,这个前边说过了,我们要记住。

      我们这样设计,我们要是想要我们的父类(SubType)的原型对象里有父父类(SuperType)的属性和方法,还有父父类原型对象的引用,不就即可以访问父类的属性和方法,还可以访问父父类的属性和方法以及父父类的原型对象的属性和方法吗?

      好啰嗦,在脑子里转一下。

      而让父类具有父父类的所有属性和方法,还有父父类的原型对象引用,是个什么东西?就是父父类的实例啊!(我理解了很久你信吗?死磕不止)。

      所以,我们把父类的原型保存的地址变成父类的实例,就可以实现,代码如下:

<script>

function SuperType () {

  this.property = true;

}

SuperType.prototype.getSuperValue = function () {

  return this.property;

};

var s = new SuperType();

function SubType() {

  this.subproperty = false;

}

SubType.prototype = new SuperType();

</script>

 

这样的继承可以表示如下:

 

 

 

如果我们var sub = new SubType();来创建一个SubType的实例,它最终包含什么的?

 

实例Sub的内存展示

SubType的原型对象(SuperType的实例)内存展示

SuperType的原型对象

subproperty:false

property:true;

constructor:SuperType

__proto__:SubType的原型对象

__proto__:SuperType的原型对象

getSuperValue();

 

 

 

 

 

 

      这样本来是父父类的所有基本属性现在变成了我们父类的原型属性,而父父类的原型对象也变成了我们的原型对象的__proto__属性,从而可以访问到父父类的原型对象内的方法和属性。

      这里有一个坑,就是我们如果本身(未继承前)原型对象里的方法和属性会被“丢失”,所以我们不能在继承前定义我们的原型属性和方法,需要继承后进行。

 

function SuperType () {

    this.property = true;

}

 

SuperType.prototype.getSuperValue = function () {

    return this.property;

};

 

var s = new SuperType();

 

function SubType() {

    this.subproperty = false;

}

 

// SubType.prototype.sayName = function () {  //放在这里会因为继承原因被丢弃!

//    console.log( this.property );

// }

 

SubType.prototype = new SuperType();

 

SubType.prototype.sayName = function () {  // 自有的原型属性和方法应该在继承后设置

    console.log( this.property );

}

var sub = new SubType();

sub.sayName();

 

还有一个坑,就是继承代码执行之后,不能用字面量方法添加新的属性和方法,因为字面量方式实际上是重新设计了一个原型对象。

<script>

function SuperType () {
    this.property = true;
}

SuperType.prototype.getSuperValue = function () {
    return this.property;
};

var s = new SuperType();

function SubType() {
    this.subproperty = false;
}

// SubType.prototype.sayName = function () {  //放在这里会因为继承原因被丢弃!
//     console.log( this.property );
// }

SubType.prototype = new SuperType();

// SubType.prototype.sayName = function () {  // 自有的原型属性和方法应该在继承后设置
//     console.log( this.property );
// }

SubType.prototype = {  // 不能用这种方式代替上一样方式,这种方式会导致继承无效,因为字面量方式实际上会重写原型,导致上上行的new SuperType()无效。
    sayName:function () {
        console.log( this.property );  // 继承无效,访问不到父类的property,会输出undefined
    }
}
var sub = new SubType();
sub.sayName();


</script>

 

posted @ 2015-07-20 18:46  定海神针  阅读(474)  评论(0编辑  收藏  举报