JS继承超详细解析

1、继承的三种方式:

原型链继承、经典继承、组合继承

2、js如何实现继承?

继承是面向对象编程中讨论最多的话题。很多面向对象语言都支持两种继承:接口继承和实现继承。前者只继承方法签名,后者继承实际的方法。接口继承在 ECMAScript 中是不可能的,因为函数没有签名。实现继承是 ECMAScript 唯一支持的继承方式,而这主要是通过原型链实现的。

3、总结

原型链继承:Dog.prototype=new Animal()

经典继承:Animal.call(this)

组合继承:方法Dog.prototype=new Animal() 、属性Animal.call(this)

一、原型链

1、原型链继承

定义:由多个原型对象(xx.prototype)连起来的原型关系链

语法:Dog继承Animal()

Dog.prototype = new Animal()

继承原理:

  • 每个构造函数都有一个原型对象,原型有一个属性指回构造函数,而实例有一个内部指针指向原型。 (图解如下:)

  • 将父的构造函数赋值给子原型对象,子原型对象就会成为父构造函数的实例,此时就会产生_proto_指针,指向父原型对象,这样子原型对象就继承了父原型对象中的方法(父构造函数上面还有一个Object)。图解如下:

例子:

检验原型链:

结论:由此可知,子实例继承了Dog、Animal、Object原型对象中的方法和实例属性

 2、原型链的方法使用

1、在子原型对象中新增方法

例子:

 注意:一定要先继承再对子原型对象新增方法

产生的问题:子实例构造函数类型模糊

解决办法:改变子原型对象constructor指向

 引发问题:

改变constructor指向是否会破坏原型链?

  • 答:不会原理链的继承是通过_proto_完成,而constructor只是说明它是哪个构造函数的实例

父构造函数的实例是否能使用子构造函数的方法?

答:不可以

2、在子原型对象中重写父原型对象的方法

例子:

父实例是否会受到影响?不会()

 3、如何破环原型链?

答:使用字面量定义子原型对象的方法

原因:当使用字面量定义方法时,_proto_就会指向Object而不是Animal(父原型对象),原来定义的Dog.prototype=new Animal()就会作废,原型链就此断开

 

例子:

4、原型链的问题

1、问题

  • 当子构造函数的实例修改父构造函数的属性值,所有的子类实例都会受到影响(原因:子实例共享的是同一个构造函数 类似于 我们原型模式遇到的问题)

  • 子实例化时,不能给父类型的构造函数传参

2、例子:

  •  通过原型图可知,d1、d2共享一个Dog.prototype,所以就变成原型模式遇到的问题。而我们修改的是Dog.prototype,因此父不会受到影响

3、d1添加,d2为什么会受到影响?

因为this存在于Animal中,而Animal被Dog.prototype调用,所以this指向了Dog.prototype,因此categeorys[ ]由原来的实例属性转变为原型属性存在于Dog.prototype中

4、解决办法:使用经典继承

经典继承

优点:可以在子类构造函数中向父类构造函数传参

缺点:

  • 1、与构造函数遇到的问题一样,方法需要占很多内存

  • 2、没有原型链,因此只继承了父类的实例属性、方法,不能继承父类构造函数的原型对象中的属性、方法

  • 3、每个子类的实例都持有父类的实例方法的副本,浪费内存,影响性能,而且无法实现父类的实例方法的复用(不能重写)

例子:

组合继承

继承方法:原型链;

继承实例属性:经典继承

例子:

猜你喜欢

转载自blog.csdn.net/qq_48109675/article/details/126771339