红宝书 第6章整理——继承部分

来源:互联网 发布:活动网络正在识别 编辑:程序博客网 时间:2024/06/01 07:48

继承

第一部分讲的都是如何创建一个类型,如果要创建多个类型,而且类型中属性方法相似度非常大,那么久可以直接用继承的方法来创建其它类 。

① 原型链

1、原型链定义+实现

继承:是面向对象语言中一个非常棒的概念。一般的面向对象语言中都支持两种继承:接口继承+实现继承。

           但是!!由于js中函数没有签名,所以只支持实现继承

            其实现继承主要依靠原型链来实现的。

下面是一个继承的例子:

////先用组合式构造一个类:Superfunction Super(){  this.value = true;}Super.prototype.getvalue = function(){   return this.value;};////再用构造函数创建第二个新类型:Subfunction Sub(){   this.subvalue = false;}//注意,接下来的方法直接用new Super构造Sub.prototype = new Super();Sub.prototype.getsubvalue = function(){   //再创建一个新方法   return this.subvalue;};///实例化var instanse = new Sub();instanse.getsubvalue();    // "true"

注意Sub.prototype = new Super();  正常此处应该写Sub.prototype的方法,但是此处直接将Sub.prototype指向了Super对象。

这时就形成了一个原型链。

instanse(实例)----->Sub(类型)----->Sub.prototype(原型)----->Super(原型)----->Super.prototype(原型)

在这个链中,后面的都算是Sub的原型,其中的东西都是可共享的。


Sub相当于可以使用除了自己后加入的方法getsubvalue,和自己的属性subvalue以外,还可以使用Super中的value和getvalue方法。

当实例中调用一个方法时,会一级一级向上找。

2、默认的原型链

实际上instanse完整的原型链为:

instanse(实例)----->Sub----->Sub.prototype----->Super----->Super.prototype----->Object----->Object.prototype

别忘了所有的函数都有一个终极的默认原型Object的实例,Object当然自己也有一个Object.prototype。

这就是为什么所有对象都有toString(),valueOf()的方法,不管有没有意义,都可以调用,因为这些都是终极原型Object.prototype中的方法.......必须得继承

3、确定原型与实例的方法

两种方法:

instanceof:

 A           是实例of         类型

friend instanceof Person;       //true

friend instanceof Object;        //true

isPrototypeOf:

原型     .   是原型of        ( 实例)

Person.prototype.isPrototypeOf(friend);      //true

Person.prototype.isPrototypeOf(Object);      //true       

4、子级添加方法

子类添加新方法,OK 。直接用子类的prototype中写就可以

当子类中创建了一个与父级中同名的方法(即重写超类型的方法),OK。

此时就会屏蔽掉超类型中原方法,注意不会对超类型产生影响,仅在子类的实例化中会执行新方法。

5、缺点

两点:

1、引用类型共享问题

 instanse(实例)----->Sub(类型)----->Sub.prototype(原型)----->Super(原型)----->Super.prototype(原型)

就这个原型链中,我们可以看出Super的构造函数也变成了原型之一,这就导致了如果Super构造函数中有属性值为引用类型(比如数组型),就会被共享,当实例中将其改变后,所有的都会被改。

之前上一部分讲创建一个类型时,出现过这种问题的是纯纯的原型模式。为了避免这个问题我们才引入的构造原型组合式。

但是此处因为继承,构造函数的也变成了原型模式。

2、不能向上级传参

只能从父级向下引用

解决办法——组合继承

② 组合继承

1、实现

组合继承的思路:因为之前构造函数被继承的缘故,导致被共享,那么在新的类型中,我们不把构造函数直接继承过来,而是变成调用父级的方式。我们可以运用call,或者apply来现场调用。

///首先还是创建父级Superfunction Super(name){  this.name = name;  this.color = ["red" , "blue"];}Super.prototype.say = function(){   alert(this.name);};///接下来创建新的类Subfunction Sub(name,age){   Super.call(this , name);    //要继承的name与color,用call函数在此处调用Super的构造函数   this.age = age;     // 自己新创建的属性age}Sub.prototype = new Super();    //方法直接继承Sub.prototype.sayage = function(){  // 自己的新方法   alert(this.age);};//测试一下var a = new Sub("jack",20);     // 创建Sub实例a.color.push("green");      //将引用类型做更改alert(a.color);     //red,blue,greena.say();           //jacka.sayage();      //20var b = new Sub("tom",33);     // 创建Sub实例alert(b.color);     //red,blueb.say();           //tomb.sayage();      //33


2、缺点

无论什么情况下,都会调用两次超类型的构造函数(就是父级的构造函数)

Super.call(this , name);    //要继承的name与color,用call函数在此处调用Super的构造函数

Sub.prototype = new Super();    //方法直接继承

顺序是先new Super();    这时实际上已经有了一套name,color,位置在超类型中,被继承

只不过后来的call又实现了一套子类中自己的name,color,将超类型中的屏蔽了。

解决办法——寄生组合式

③原形式继承+寄生式继承+寄生组合式继承

原型式:可以在没有预先定义构造函数的情况下实现继承,本质是先浅复制,再改造

寄生式:与原形式类似,也是先创建一个对象,然后再改造

寄生组合式:集寄生式和组合式,是实现引用类型最理想的继承方式。,只调用一次超类型的构造函数

0 0