《JavaScript》——面向对象之继承

     继承是面向对象中一个比较核心的概念。 其他正统面向对象语言都会用两种方式实现继承:一个是接口实现,一个是继承。而 ECMAScript 只支持继承,不支持接口实现,而实现继承的方式依靠原型链完成。在JavaScript中的继承中,分了好几类继承,可以说是伴随着问题的出现,继承的方法也升级了,不光是原型链继承,还有组合继承、原型继承、寄生式继承、寄生组合继承等等。他们伴随着不同问题的出现而出现,下面我分别介绍一下这几种继承方式。

     1、原型链式继承   

<span style="font-family:KaiTi_GB2312;font-size:18px;">function Box() { //Box 构造
this.name = '美女';
}
function Desk() { //Desk 构造
this.age = 100;
}
Desk.prototype = new Box(); //Desk 继承了 Box,通过原型,形成链条
var desk = new Desk();
alert(desk.age);
alert(desk.name); //得到被继承的属性</span>
     缺点:原型链式继承实例化后的初始值是一样的,不能改变,也无法复用,组合继承(原型链+借用构造函数)来解决这种问题。

     2、组合继承(原型链+借用构造函数)

<span style="font-family:KaiTi_GB2312;font-size:18px;">
function Box(age){
	this.name=['林志玲','范冰冰'];
	this.age=age;
}

Box.prototype.run=function(){
	return this.name+'的年龄是'+this.age;
}

function Desk(age){
	Box.call(this,age);                           //对象冒充,这里的作用是传递参数,只会讲Box的实例中的方法和属性传递给Desk(),原型中的信息不会传递。
}

// var desk=new Desk(20);
// alert(desk.name+'你们好吗???');                //这里返回  林志玲,范冰冰你们好吗??? 原因是Desk()函数内部使用了对象冒充。
// alert(desk.run());                                 //没有设置原型链继承,run()方法不会被继承下来。

Desk.prototype=new Box();                            //使用原型链继承,将Box()的原型和实例的所有信息都传给Desk()
var desk=new Desk(20);
alert(desk.name+'你们好吗???');                  //返回  林志玲,范冰冰你们好吗???
alert(desk.run());                                  //返回  林志玲,范冰冰的年龄是 20
</span>

     组合继承的弥补了原型链式继承穿参和共享问题,但是缺点是每次实例化一个对象的实例,都需要两次调用超类Box().而寄生组合继承就能解决此问题。寄生组合继承一会在说,先说一下原型式继承。

     3、 原型式继承

<span style="font-family:KaiTi_GB2312;font-size:18px;">//
function obj(o) { //传递一个字面量函数
function F() {} //创建一个构造函数
F.prototype = o; //把字面量函数赋值给构造函数的原型
return new F(); //最终返回出实例化的构造函数
}

var box = { //字面量对象
name : 'Lee',
arr : ['哥哥','妹妹','姐姐']         //添加一个数组,数组时引用类型
};

var box1 = obj(box);               //传递
alert(box1.name);                   //返回Lee
box1.name = 'Jack';              //将name改成jack
alert(box1.name);                  //返回Jack

alert(box1.arr);
box1.arr.push('父母');            //arr属性是一个数组,这里往数组里多添加一个父母。
alert(box1.arr);


var box2 = obj(box);  //传递
alert(box2.name);      //返回Lee,而不是Jack,子类之间,值类型没有共享。
alert(box2.arr);           //返回哥哥,妹妹,姐姐,父母,子类之间,引用类型共享了。</span>
     这种继承借助原型并基于已有的对象创建新对象实例,同时还不必因此创建自定义类型(不用自己添加属性和方法)。

     4、寄生式继承(原型继承+工厂方法模式)

<span style="font-family:KaiTi_GB2312;font-size:18px;">function obj(o){
	function F(){}
	F.prototype=o;
	return new F();
}

function create(o){
	f=obj(o)
	f.run=function(){
		return this.family;
	}
	return f;
}

var box={
	name:'林志颖',
	age:22,
	family:['引用类型1']
}

var box1 = create(box); //传递
alert(box1.name);           //继承的是box对象,输出 林志颖
box1.name='刘亦菲';     //将自己实例中name属性改成刘亦菲,更改的是子类型的name
alert(box1.name);          //输出刘亦菲
alert(box1.run());            //输出的是引用类型1,
box1.family.push('引用类型2');//输出的是引用类型1,引用类型2,更改的是超类型的family
alert(box1.run());

var box2 = create(box);  //传递
alert(box2.name);            //继承的是box对象,输出 林志颖 并没有输出刘亦菲
alert(box2.run());  </span>
     寄生式继承把原型式+工厂模式结合而来,目的是为了封装创建对象的过程。

     5、寄生组合继承 解决多次实例化时,多次调用超类问题。   

<span style="font-family:KaiTi_GB2312;font-size:18px;">//中转函数
function obj(o){
	function F(){}
	F.prototype=o;
	return new F();
}
//寄生函数
function create(box,desk){
	f=obj(box.prototype);      //这里传的是Box的原型对象
	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('美女',25)
alert(desk.run()); //返回美女,25</span>
    小结

    这几种继承方式都介绍完了,我只是了解到皮毛,但是它们在项目中的真正作用哪怕只有在锻炼项目时才会发现,现在说什么都是嘴把式,再有真把式之前,这些理论知识也是很有必要的,就让项目再升华这几种继承方式吧!
  

你可能感兴趣的:(JavaScript,Web,web开发)