您的位置:首页 > Web前端 > JavaScript

JS学习笔记——JavaScript继承的6种方法(原型链、借用构造函数、组合、原型式、寄生式、寄生组合式)

2017-05-18 23:03 1311 查看
JavaScript继承的6种方法

1,原型链继承

2,借用构造函数继承

3,组合继承(原型+借用构造)

4,原型式继承

5,寄生式继承

6,寄生组合式继承

1.原型链继承.

<script type="text/javascript">
function Person(name,sex)
{
this.name=name;
this.sex=sex;
this.friends=['李四'];
this.getName=function(){
alert(this.name);
}
}
Person.prototype.id=1;

function Boy(age)
{
this.age=age;
this.getAge=function(){
alert(this.age);
}

}
//继承
Boy.prototype=new Person("张三","男");

var boy=new Boy(16);

alert(boy.name);              //张三
boy.getAge();               //16
alert(boy.id);                 //1

//属性共享问题
console.log(boy.friends);            //李四

var boy2=new Boy(17);
boy2.friends.push('王五');  //修改boy2的friends属性的同时也影响了boy的属性

console.log(boy.friends);            //李四 王五

//验证能否使用instanceof 和 isPrototypeof
console.log(boy instanceof Person);                 //true
console.log(Person.prototype.isPrototypeOf(boy));   //true
</script>


特点:既继承了父类的模板,又继承了父类的原型对象。

缺点:只能在父类设置一些参数,子类不能灵活传参,不符合面向对象的思想,包含引用类型值的属性始终都会共享相应的值。



2.借用构造函数继承

<script type="text/javascript">
//父类
function Person(name,sex)
{
this.name=name;
this.sex=sex;
this.friends=['李四'];
}
Person.prototype.id=1;
//子类
function Boy(name,sex,age)
{

//借用
Person.call(this,name,age);

this.age=age;
this.getAge=function(){
alert(this.age);
}

}

var boy=new Boy("张三","男",16);
alert(boy.name);  //张三

boy.getAge();        //16

alert(boy.id);  //undefined  没有继承父类的原型对象

//属性共享问题 ————不会有共享

//验证能否使用instanceof 和 isPrototypeof
console.log(boy instanceof Person);                 //false
console.log(Person.prototype.isPrototypeOf(boy));   //false
</script>


特点:只继承了父类的模板,不继承父类的原型对象。

缺点:方法都在构造函数中定义,不能做到函数复用。



3.组合继承(原型+借用构造)最常用的继承模式

<script type="text/javascript">
//父类
function Person(name,sex)
{
this.name=name;
this.sex=sex;

}
Person.prototype.id=1;
//子类
function Boy(name,sex,age)
{

//借用构造函数  继承父类的模板
Person.call(this,name,age);

this.age=age;
this.getAge=function(){
alert(this.age);
}

}

//不传递参数,继承父类的模板,继承父类的原型对象 id
Boy.prototype=new Person();

var boy=new Boy("张三","男",16);
alert(boy.name);  //张三

boy.getAge();        //16

alert(boy.id);  //1

//属性共享问题 ————除了父类的原型对象,不会有共享

//验证能否使用instanceof 和 isPrototypeof
console.log(boy instanceof Person);                 //true
console.log(Person.prototype.isPrototypeOf(boy));   //true
</script>


特点:既继承了父类的模板,又继承了父类的原型对象。

缺点:做了3件事,继承了父类两次模板,继承了一次原型对象

原型式继承解决了这个问题



4.原型式继承

<script type="text/javascript">
var person={
name:'张三',
sex:'男',
friends:['李四']
}

function object(obj)
{
function F(){}   //创建一个空的构造函数
F.prototype=obj;  //将传入的对象作为这个构造函数的原型
return new F();   //返回一个新实例  对传入的对象进行了一次浅复制
}

var boy=object(person);
//ECMAScript 5 新增了Object.create()方法 与本例 object 方法行为相同
//可改为 Object.create(person);

alert(boy.name);  //张三

//但是原型式同样存在属性共享的问题
//例如:

var girl=object(person);
girl.friends.push('王五');

alert(boy.friends); //李四 王五
alert(girl.friends);//李四 王五

//修改girl中的friends属性  boy 也会受到影响

//无法使用 instanceof 和 isPrototypeof

</script>


创造的目的是基于已有的对象创建新的对象,同时还不必因此创建自定义类型。

包含引用类型值的属性始终都会共享相应的值,就像使用原型模式一样。



5.寄生式继承

<script type="text/javascript">
function object(obj)
{
function F(){}   //创建一个空的构造函数
F.prototype=obj;  //将传入的对象作为这个构造函数的原型
return new F();   //返回一个新实例  对传入的对象进行了一次浅复制
}

function Person(person)
{
var clone=object(person);
clone.getSex=function(){
alert(this.sex);
}
return clone;
}
var person={
name:'张三',
sex:'男',
friends:['李四']
}
var boy=Person(person);
boy.getSex();         //男

//属性共享问题————因为传入同一个实例,所以存在共享问题
var boy2=Person(person);
boy2.friends.push('王五');

alert(boy.friends);     //李四  王五

//验证能否使用instanceof 和 isPrototypeof
console.log(boy instanceof Person);                 //false
console.log(Person.prototype.isPrototypeOf(boy));   //false
</script>


与构造函数模式类似,不能做到函数复用会降低效率。

6.寄生组合式继承

<script type="text/javascript">

function object(o)
{
function F(){}
console.log(o);
F.prototype=o;
return new F();

}
function extend(subType,superType)
{
var prototype=object(superType.prototype);  //创建父类的一个副本
prototype.constructor=subType;                //为创建的副本添加失去默认的构造函数
subType.prototype=prototype;                //将新创建的对象赋值给子类的原型
}
function Person(name)
{
this.name=name;
this.friends=['李四'];
}
function Boy(name,sex)
{
Person.call(this,name);             //借用构造函数  继承父类的模板
this.sex=sex;
}

extend(Boy,Person);  //继承

var boy=new Boy('张三','男');

alert(boy.name);     //张三

//属性共享问题————不会存在共享问题
var boy2=new Boy('张三','男');
boy2.friends.push('王五');

alert(boy.friends);     //李四

//验证能否使用instanceof 和 isPrototypeof
console.log(boy instanceof Person);                 //false
console.log(Person.prototype.isPrototypeOf(boy));   //false
</script>


寄生式组合继承解决了组合继承会调用两次父类构造函数,子类最终会包含父类的全部实例属性,父类的属性不是必须的,子类的属性会覆盖父类的属性。

寄生式组合继承只调用一次父类构造函数,原型链能保持不变,因此还能够正常使用instanceof和isPrototypeOf(),YUI的extend方法就使用的是寄生组合继承,是实现基于类型继承的最有效的方式。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐