Javascript高级程序设计——14.面向对象与原型(3)

继承

A.继承是面向对象中一个比较核心的概念。

B.正统面向对象语言有两种方式实现继承:

   (1)接口实现;

   (2)继承

C.在ECMAScript只支持继承,不支持接口实现,

而实现继承的方式依靠原型链完成


1、继承方式1——通过原型链实现

(1)被继承的函数——“超类型”(父类、基类)

(2)继承的函数——“子类型”(子类、派生类)

作用:通过原型链继承,可将“超类型”实例化后的对象实例,赋值给“子类型”的原型属性

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


Box.prototype.name='Jack';


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


//通过原型链继承,超类型实例化后的对象实例,赋值给子类型的原型属性
//new Box()会将Box构造的信息和原型信息交给Desk
Desk.prototype=new Box();  //Desk的原型得到
//Table.prototype=new Desk();


var desk=new Desk();
alert(desk.name);    //遵循就近原则,实例中有,就返回,没有就去查找原型
//var table=new Table();
//alert(desk.age);   //100
//alert(desk.name);  //Lee


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

上述案例代码中,子类型从属于它的超类型,

同时,在进行变量属性查找时,遵循“就近原则”:

——即先在实例化对象中查找,若有,就返回该属性赋值;若无,就继续查找原型中的该属性。


2、继承方式2——借用构造函数/使用对象冒充继承

目的:解决引用共享和超类型无法传参

作用:实现伪造对象,经典继承。

步骤1:先创建一个构造函数,实例化对象(有this标识)

步骤2:再创建一个构造函数,只作为“对象冒充”使用

a、所谓“对象冒充”,即只继承构造函数中的信息。

例如:

Box.call(this,name,age) 

b、对象冒充,不能继承原型函数的信息。

例如:

Box.prototype.family='家庭';

alert(desk.family);   //undefined,不能继承原型中的;

步骤3:为构造函数添加格外的信息,并返回。

//1.创建一个构造函数;
function Box(name,age){
	this.name=name;
	this.age=age;
	this.family=['哥哥','姐姐','妹妹'];
	//当引用类型,放到构造函数,就会被共享;
}


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

//2.创建一个构造函数用于对象冒充
function Desk(name,age){
	Box.call(this,name,age)     //对象冒充,对象冒充只能继承构造函数中的信息;
}

//3.传递参数;
var desk=new Desk('Lee',100);
alert(desk.name);  //Lee
//alert(desk.family);   //undefined,不能继承原型中的;


alert(desk.family);   //哥哥、姐姐、妹妹
desk.family.push('弟弟');
alert(desk.family);   //哥哥、姐姐、妹妹、弟弟


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

3、继承方式3——组合继承

(1)概念:组合继承=原型链+借用构造函数

由于没有原型,则实现不了复用,必须使用组合继承

(2)作用:实现伪造函数、分享、复用


实现过程步骤如下——
步骤1:构造函数实例化对象

function Box(name,age){}

步骤2:为构造函数的原型属性添加方法

Box.prototype.run=function(){}

步骤3:采用对象冒充

Box.call(this,name,age);

步骤4:将实例化方法放在构造函数对象的原型里

Desk.prototype=new Box();     //原型链继承,只继承原型中的;

步骤5:调用Box(),并赋值。

//1、构造函数实例化对象
function Box(name,age){
	this.name=name;
	this.age=age;
	this.family=['哥哥','姐姐','妹妹'];
}

//2、原型中
Box.prototype.run=function(){
	return this.name+this.age;
};


//3、构造函数中的方法,放在构造里,每次实例化,都分配一个内存地址,浪费,所以最好放在原型里

function Desk(name,age){
	//第二次调用Box
	Box.call(this,name,age)    //对象冒充
}

//第一次调用Box
Desk.prototype=new Box();     //原型链继承,只继承原型中的;


var desk=new Desk('Lee',100);
alert(desk.run());  //返回null,无值


4、继承方式4——原型式继承

(1)先创建一个临时中转函数,

function obj(o){}

(2)采用字面量方式创建对象

var box={

...

};

(3)为对象赋值并进行调用

//临时中转函数
function obj(o){  //o表示将要传递进入的一个对象;
	function F(){ } //F构造是一个临时新建的对象,用来存储传递过来的参数;
	F.prototype=o;   //将o对象实例赋值给F构造的原型对象;
	return 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.family);
box1.family.push('弟弟');
alert(box1.family);


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



5、继承方式5—— 寄生式继承

(1)概念:寄生式继承=原型+工厂模式
(2)目的:为了封装继承对象
(3)实现流程见步骤——

步骤1:创建临时中转函数

function obj(o){...}

其中o为临时传递的对象,创建的函数function F(){}为临时函数,

步骤2:创建寄生函数

function create(o){}

步骤3:字面量方式创建对象

var box={};

步骤4:调用寄生函数,并赋值

//临时中转函数
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());




6、继承方式6—— 寄生组合继承

由于之前的组合式继承(最常用),但是对于超类型在使用中会被调用两次
     一次是创建子类型的时候,另一次是在子类型构造函数的内部;
为解决此问题,所以采用寄生组合继承

步骤1:创建临时中转函数

function obj(o){...}

其中o为临时传递的对象,创建的函数function F(){}为临时函数,

步骤2:创建寄生函数

function create(o){}

步骤3:构造函数方式创建实例化对象

function Box(){...}

步骤4:为对象添加原型的方法

Box.prototype.run=function(){}

步骤5:对象冒充方式创建另一个对象

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

步骤6:采用“寄生组合方式”实现继承

create(Box,Desk);

步骤7:用构造函数方法创建对象,并赋值;

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


//临时中转函数
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;
	//return 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);


var desk=new Desk('Lee',100);
alert(desk.run());
//Lee 100 运行中...
alert(desk.constructor);
//function Desk(name,age){this.name+this.age;}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值