JavaScript之面向对象与原型笔记整理--------继承(4)

继承是面向对象中一个比较核心的概念,其他正统面向对象语言都会用两种方式实现继承:一个是接口实现,一个是继承。而ECMAScript只支持继承,不支持接口继承,而实现继承的方式依靠原型链完成。

1.原型链实现继承

function Box(){
      this.name = 'Lee';   //被继承的函数叫做超类型(父类,基类)
}
function Desk(){
      this.age = 100;       //继承的函数叫做子类型(子类,派生类)
}
function Table(){
this.level = 'AAAAA';
}
//通过原型链继承,超类型实例化后的对象实例,赋值给子类型的原型属性 //new Box()会将Box构造里的信息和原型里的信息都交给Desk
//Desk()的原型,得到的是Box的构造+原型里的信息 Desk.prototype = new Box(); Table.prototype = new Desk();
var desk = new Desk(); console.log(desk.name); //Lee
var table = new Table();
console.log(table.name); //Lee
console.log(table.age); //100

                                                                    原型链继承流程图

注意:以上原型链继承还缺少一环,那就是Object,所有的构造函数都继承自Object。而继承Object是自动完成的,并不需要程序员手动继承。

存在的情况:

function Box(){
    this.name = 'Lee';
}
Box.prototype.name = 'Luck';
function Desk(){
    this.age = 100;
}
Desk.prototype = new Box();

var box = new Box();
var desk = new Desk();

console.log(desk.name);  //Lee   就近原则,实例里有就返回,没有就查找原型

//子类型从属于自己活他的超类型
console.log(desk instanceof Object);  //true 自动继承Object
console.log(desk instanceof Desk);    //true
console.log(desk instanceof Box);      //true
console.log(box instanceof Desk);      //false

继承也有之前问题,比如字面量重写原型会中断关系,使用引用类型的原型,并且子类型还无法给超类型传递参数。

为了解决引用共享超类型无法传参的问题,采用一种叫借用构造函数的技术,或者称为对象冒充(伪造对象、经典继承)的技术来解决这两种问题。

2.对象冒充继承

//使用对象冒充继承
function Box(name,age){
      this.name = name;
      this.age = age;
}
//若在此定义原型信息
Box.prototype.family = '家庭';
function Desk(name,age){    //对象冒充,对象冒充只能继承构造函数里的信息
      Box.call(this,name,age);
}

var desk = new Desk('Lee',20);
console.log(desk.name);   //Lee
console.log(desk.family );   //undefined 继承不到原型信息

借用构造函数虽然解决了刚才两种问题,但没有原型,复用(里面有方法必须保持独立,构造函数里的方法,放在构造里,每次实例化,都会分配一个内存地址,浪费空间,所以最好放在原型里,保证多次实例化只有一个地址)则无从谈起。所以,需要原型链+借用构造函数的模式,这种模式称为组合继承。

3.组合继承(应用广泛)

原型链+借用构造函数的模式

 1 function Box(name,age){
 2     this.name = name;
 3     this.age = age;
 4 }
 5 
 6 Box.prototype.run = function(){
 7     return this.name + this.age;
 8 }
 9 
10 function Desk(name,age){
11     Box.call(this,name,age);   //对象冒充只继承构造函数里的信息   第二次调用Box
12 }
13 Desk.prototype = new Box();    //原型继承只继承原型里的信息   第一次调用Box

14 var desk = new Desk('Lee',20);
15 console.log(desk.run()); //Lee20 若没有第十三行,则继承不到,会报错

解决的问题:

(1)传参问题

(2)原型链方法的继承

(3)方法的共享

 4.原型式继承

这种继承借助原型并基于已有的对象创建新对象,同时还不必因此创建自定义类型。

//临时中转函数
function obj(o){       //o表示将要传递进去的一个对象
    function F(){};    //F构造是一个临时新建的对象 
    F.prototype = o;  //将o对象实例赋值给F构造的原型对象
    return new F();    //最后返回这个得到传递过来对象的对象实例 
}
//F.prototype = o; 其实就相当于Desk.prototype = new Box();
//这是字面量的声明方法,相当于var box = new Box();
var box = {
    name:'Lee',
    age:20,
    family:['哥哥']
}
//box1就等于new F()
var box1 = obj(box);
console.log(box1.name);  //Lee
box1.family.push('弟弟');
var box2 = obj(box);
console.log(box2.family); //哥哥,弟弟   引用类型共享了

其实原型式继承就相当于原型链继承。仅此变了一下结构。

缺点:引用类型共享了

5.寄生式继承

寄生式继承=原型式继承+工厂模式

目的是为了封装创建对象的过程。

//临时中转函数
function obj(o){
    function F(){};
    F.prototype = o;
    return new F();
}
//寄生函数
function create(o){
    var f = obj(o);
    f.run = function(){             //对F进行扩展
        return this.name + '!!';  
    }   
    return f;
}
var box = {
    name:'Lee',
    age:20,
}
var box1 = creat(box);
console.log(box1.name);      //Lee
console.log(box1.run());      //Lee!!

此时,box1不仅仅拥有了box的属性和方法,还拥有了自己的run()方法。

注意:使用寄生式继承方式来为对象添加函数,由于不能达到函数复用,导致效率变低,这与构造函数模式类似。

组合式继承是JS最常用的继承模式,但也存在些问题,就是超类型在使用过程中被调用两次:一次是创建子类型的时候,另一次是在子类型构造函数的内部。

寄生组合继承解决了两次调用的问题。

6.寄生组合继承

 1 //临时中转函数
 2 function obj(o){
 3     function F(){};
 4     F.prototype = o;
 5     return new F();
 6 }
 7 //寄生函数
 8 function create(box,desk){
 9     var f = obj(box.prototype);
10     f.constructor = desk;     //调整原型构造指针使得desk.constructor指向自己,不加这句的话,指向Box
11     desk.prototype = f;
12 }
13 function Box(name,age){
14     this.name = name;
15     this.age = age;
16 }
17 Box.prototype.run = function(){
18     return this.name + this.age +'!!';
19 }
20 function Desk(name,age){
21     Box.call(this,name,age);  //对象冒充
22 }
23 //通过寄生组合继承老师先继承
24 create(Box,Desk);
25 var desk = new Desk('Lee',20);
26 console.log(desk.run());      //Lee20!!

猜你喜欢

转载自www.cnblogs.com/manru75/p/9484335.html