首页 > js学习 > js基础知识 > javascript中的面向对象的继承
2016
12-16

javascript中的面向对象的继承

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

function Box(){this.name = 'Lee';}//Box构造

function Desk(){this.age = 100;}//Desk构造

Desk.prototype = new Box(); //Desc继承了Box,通过原型,形成链条

var desk = new Desk();

alert(desk.age);

alert(desk.name);//得到被继承的属性

function Table() {this.level = 'AAAAA';}//Table构造

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

var table = new Table();

alert(table.name);//继承了Box和Desk

如果要实例化table,那么Desk实例中有age=100,原型中增加相同的属性(Desk.prototype.age = 200),那么table.age会打印实例的值100

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

经过继承后的实例,他们的从属关系会怎样呢?

alert(table instanceof Object); //true

alert(desk instanceof Table); //false,desk是table的超类

alert(table instanceof Desk); //true

alert(table instanceof Box); //true

在JavaScript里,被继承的函数称为超类型(父类,基类也行,其他语言叫法),继承的函数称为子类型(子类,派生类)。继承也有之前问题,如字面量重写原型会中断关系,使用引用类型的原型,并且子类型还无法给超类型传递参数。

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

function Box(age) {

this.name = ['Lee', 'Jack', 'Hello'];

this.age = age;

}

Box.prototype.height=175; //原型属性

function Desk(age) {

Box.call(this, age); //对象冒充,给超类型传参

}

var desk = new Desk(200);

alert(desk.age);//200

alert(desk.name);//Lee,Jack,Helloa

alert(desk.height);//undefined,对象冒充只能借用实例属性,不能借用原型属性

desk.name.push('AAA'); //添加的新数据,只给desk

alert(desk.name);//Lee,Jack,Hello,AAA

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

function Box(age) {

this.name = ['Lee', 'Jack', 'Hello'];

this.age = age;

}

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

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

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

var desk = new Desk(100);

alert(desk.run());

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

function obj(o) { //传递一个字面量函数

function F() {} //创建一个构造函数

F.prototype = o; //把字面量函数赋值给构造函数的原型

return new F(); //最终返回出实例化的构造函数

}

var box = { //字面量对象

name : 'Lee',

arr : ['哥哥','妹妹','姐姐']

};

var box1 = obj(box); //传递

alert(box1.name);

box1.name = 'Jack';

alert(box1.name);

alert(box1.arr);

box1.arr.push('父母');

alert(box1.arr);

var box2 = obj(box); //传递

alert(box2.name);

alert(box2.arr); //引用类型共享了

寄生式继承把原型式+工厂模式结合而来,目的是为了封装创建对象的过程。

function create(o) { //封装创建过程

var f= obj(o);

f.run = function () {

return this.arr; //同样,会共享引用

};

return f;

}

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

function Box(name) {

this.name = name;

this.arr = ['哥哥','妹妹','父母'];

}

Box.prototype.run = function () {

return this.name;

};

function Desk(name, age) {

Box.call(this, name); //第二次调用Box

this.age = age;

}

Desk.prototype = new Box(); //第一次调用Box

以上代码是之前的组合继承,那么寄生组合继承,解决了两次调用的问题。

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) {

this.name = name;

this.arr = ['哥哥','妹妹','父母'];

}

Box.prototype.run = function () {

return this.name;

};

function Desk(name, age) {

Box.call(this, name);

this.age = age;

}

inPrototype(Box, Desk); //通过这里实现继承

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

desk.arr.push('姐姐');

alert(desk.arr);

alert(desk.run()); //只共享了方法

var desk2 = new Desk('Jack', 200);

alert(desk2.arr); //引用问题解决

最后编辑:
作者:qingheluo
这个作者貌似有点懒,什么都没有留下。