js实现继承的方式

一、原型链


function Parent1(name){
    this.name=name;
    this.role='father';
    this.play=[1,2,3];
}
function Child1(name){
    this.name=name;
    this.role='child';
}
Child1.prototype=new Parent1();//继承Parent1
var s1=new Child1("Nike")
var s2=new Child1("Mary")
s1.play.push(4);
s1.play //[1,2,3,4]
s2.play //[1,2,3,4],s2的play属性也发生了改变
s1 instanceof Child1  //true
s1 instanceof Parent1 //true,s1是Child1和Parent1的实例
s1.constructor===Child1 //false,可见无法找到自己的直接原型
s1.constructor===Parent1 //true

缺点:

1、包含引用类型的原型属性会被所有实例共享(这也是为什么要在构造函数中,而不是原型对象中定义属性的原因。
2、实例无法正确判断谁是自己的直接原型。

二、借用构造函数

function Parent2(name){
    this.name=name;
    this.friends=['red','blue']
}
Parent2.prototype.sayName=function(){
    console.log(this.name)
}
function Child2(name){
    Parent2.call(this)//"借调"了超类的构造函数
    // Parent2.call(this,'Nike')//还可以继承的同时,给子类传参,这是借用构造函数的一个优势
}
var s3=new Child2("Nike")
var s4=new Child2("Mary")
s3.friends.push('green')
s3.friends //['red','blue','green']
s4.friends //['red','blue'],每个实例都可以拥有自己独有的引用类型。解决了方法一存在的问题
s3 instanceof Child2  //true
s3 instanceof Parent2 //false,s3是Child2和Parent2的实例,但是这里没有检测出是Parent2的实例
s3.constructor===Child2 //true,可见可以找到自己的直接原型
s3.constructor===Parent2 //false
s3.sayName();//Uncaught TypeError: s3.sayName is not a function,可见借用构造函数的方法不能继承父类原型链上的方法。

缺点:缺点:解决了引用类型被共享的问题,也解决了原型链方法找不到直接父类的问题,但是该方法的子类不能继承父类的原型链(即prototype上的方法),并且方法都在构造函数中定义,那么函数定义就无从谈起了。
 

三、组合继承

function Parent3(name){
    this.name=name;
    this.role='father';
    this.play=[1,2,3];
}
function Child3(name){
    Parent3.call(this)//第二次调用Parent3
    this.name=name;
    this.role='child';
}
Child1.prototype=new Parent1();//继承Parent3,第一次调用Parent3
var s5=new Child3("Nike")
var s6=new Child3("Mary")
s5.play.push(4);
s5.play //[1,2,3,4]
s6.play //[1,2,3],每个实例都可以拥有自己独有的引用类型。
s5 instanceof Child3  //true
s5 instanceof Parent3 //false,s5是Child3和Parent3的实例,但是这里没有检测出是Parent3的实例
s5.constructor===Child3 //true,可见找到自己的直接原型
s5.constructor===Parent3 //false

缺点:无论在什么情况下都会调用两次超类型构造函数,一次是在创建子类原型的时候,另一次是在子类构造函数的内部。

四、组合继承优化

function Parent4(name){
    this.name=name;
    this.play=[1,2,3]
}
function Child4(name){
    Parent4.call(this)//"借调"了超类的构造函数
}
Child4.prototype=Parent4.prototype;//引用通一个对象

var s7=new Child4("Nike")
var s8=new Child4("Mary")
s7.play.push(4);
s7.play //[1,2,3,4]
s8.play //[1,2,3],每个实例都可以拥有自己独有的引用类型。
s7 instanceof Child4  //true
s7 instanceof Parent4 //true,检测出是Parent4和Child4的实例
s7.constructor===Child4 //false,可见不能找到自己的直接原型
s7.constructor===Parent4 //true

缺点:解决了方法三调用两次父类构造函数的问题,但是该方法又没有办法找到自己的直接父类。

五、寄生组合式继承

function Parent5(name){
    this.name=name;
    this.role='father';
    this.play=[1,2,3];
}
function Child5(name){
    Parent5.call(this);
    this.name=name;
    this.role='child';
}

Child5.prototype=Object.create(Parent5.prototype);//隔离①
// Child5.prototype=Parent5.prototype;
Child5.prototype.constructor=Child5;//覆盖② 
var s9=new Child5("Nike")
var s10=new Child5("Mary")
s9.play.push(4);
s9.play //[1,2,3,4]
s10.play //[1,2,3],每个实例都可以拥有自己独有的引用类型。
s9 instanceof Child5  //true
s9 instanceof Parent5 //true,检测出是Parent5和Child5的实例
s9.constructor===Child5 //true,可见可以找到自己的直接原型
s9.constructor===Parent5 //false

注:

1、Object.create()是将对象继承到__proto__上;
2、Object.create()方法接收两个参数,一个用作新对象原型的对象和(可选的)一个为新对象定义额外属性的对象。在传入一个参数的情况下,Object.create()和object()方法的行为相同。


 ①,②解决了找不到直接原型的问题,该方法的每一步都可以得到正确答案。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值