面向对象与原型---继承

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

一、原型+对象构造之间的关系结构像链条一样,称原型链。

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

如果要实例化table,那么Desk 实例中有age=100,原型中增加相同的属性age=200,
最后结果是多少呢?
Desk.prototype.age = 200; //实例和原型中均包含age
PS:以上原型链继承还缺少一环,那就是Obejct,所有的构造函数都继承自Obejct。而
继承Object 是自动完成的,并不需要程序员手动继承。

从属关系

function Box() {                    //被继承的函数叫做超类型(父类,基类)
    this.name = 'Lee';
}

Box.prototype.name = 'Jack';

function Desk() {                //继承的函数叫做子类型(子类,派生类)
    this.age = 100;
}

Desk.prototype = new Box();        //通过原型链继承

var box = new Box();
var desk = new Desk();
//alert(desk.name);                    //就近原则,实例里有,就返回,没有就去查找原型

//子类型从属于自己或者他的超类型
//alert(desk instanceof Object);
alert(desk instanceof Desk);
alert(desk instanceof Box);
alert(box instanceof Desk);

字面量重写原型会中断关系,使用引用类型的原型,并且子类型还无法给超类型传递参数

二、对象冒充(伪造对象、经典继承)/借用构造函数

//使用对象冒充继承

function Box(name, age) {
    this.name = name;
    this.age = age;
    this.family = ['哥哥','姐姐','妹妹'];    //引用类型,放在构造里就不会被共享 
}

//Box.prototype.family = '家庭';

function Desk(name, age) {
    Box.call(this, name, age)                //对象冒充,对象冒充只能继承构造里的信息//desk冒充Box
}


var desk = new Desk('Lee', 100);
alert(desk.family);
desk.family.push('弟弟');
alert(desk.family);


var desk2 = new Desk('Lee', 100);
alert(desk2.family);

 

三、借用构造函数虽然解决了刚才两种问题,但没有原型,复用则无从谈起。所以,我们需
要原型链+借用构造函数的模式,这种模式成为组合继承。(用的比较多)

function Box(name, age) {
    this.name = name;
    this.age = age;
    this.family = ['哥哥','姐姐','妹妹'];
}

Box.prototype.run = function () {
    return this.name + this.age + '运行中...';
};

//构造函数里的方法,放在构造里,每次实例化,都会分配一个内存地址,浪费,所以最好放在原型里,保证多次实例化只有一个地址

function Desk(name, age) {
    Box.call(this, name, age)                    //对象冒充
}

Desk.prototype = new Box();                //原型链继承


var desk = new Desk('Lee', 100);
alert(desk.run());

四、原型继承

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

//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 : 100,
    family : ['哥哥','姐姐','妹妹']
};

//box1就等于new F()
var box1 = obj(box);
//alert(box1.name);
alert(box1.family);
box1.family.push('弟弟');
alert(box1.family);

var box2 = obj(box);
alert(box2.family);                    //引用类型的属性共享了

五、寄生式继承把原型式+工厂模式结合

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

//临时中转函数
function obj(o) {                
    function F() {}                
    F.prototype = o;            
    return new F();            
}

//寄生函数
function create(o) {
    var f = obj(o);
    f.run = function () {
        return this.name + '方法';
    }
    return f;
}

var box = {
    name : 'Lee',
    age : 100,
    family : ['哥哥','姐姐','妹妹']
};


var box1 = create(box);
alert(box1.run());

六、寄生组合继承

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

//临时中转函数
function obj(o) {                
    function F() {}                
    F.prototype = o;            
    return new F();            
}


//寄生函数
function create(box, desk) {
    var f = obj(box.prototype);
    f.constructor = desk;                //调整原型构造指针
    desk.prototype = f;
}

function Box(name, age) {
    this.name = name;
    this.age = age;
}

Box.prototype.run = function () {
    return this.name + this.age + '运行中...'
}

function Desk(name, age) {
    Box.call(this, name, age);                //对象冒充
}

//通过寄生组合继承来实现继承
create(Box, Desk);                            //这句话用来替代Desk.prototype = new Box();


var desk = new Desk('Lee', 100);
alert(desk.run());
alert(desk.constructor);

 

posted @ 2015-03-23 00:17  laugh  阅读(286)  评论(0编辑  收藏  举报