什么是继承?
我认为利用原型链让一个引用类型,可以使用另一个引用类型的属性和方法,就叫做继承。
继承方式
1.原型链
使用原型链,让一个引用类型继承另外一个引用类型的属性和方法。
1 | function Parent(){ |
打印的child如图:
这里的继承其实是重写了Child的原型对象,使它指向了Parent构造函数的实例。
缺点:引用类型会被所有实例共享,如下
1 | function Parent(){ |
2.借用构造函数
子构造函数通过new关键字调用的时候,调用到内部调用父构造函数,会创建新的实例。
1 | function Parent(){ |
打印的child1,如图
其实两个new关键字创建出了2个实例里的arr是不同的
3.组合继承
整合原型链和借用构造函数的方式,其实就是在实例上创建新的属性,不像前面是直接共享使用原型链上的属性。
1 | function Parent(name){ |
先看child1打印结果:
可以看到实例上有个arr数组,push操作是往这个arr数组里压入
再看child2打印结果:
跟原型链方式比较:区别是原型链方式没有为实例新建属性,而是在[[Prototype]]上,相同的引用地址指向同一个对象。如果修改__proto__
上的arr属性,就会被修改。而且有两次调用Parent函数
1 | function Parent(name){ |
4.原型式继承
这种继承方式要求,使一个对象作为另一个对象的基础,也就是创建一个新的对象,让它出现在另一个对象的[[Prototype]]上。
1 | var person = { |
打印的anotherPerson如图:
5.寄生式继承
通过函数,创建一个对象,并在函数内为这个对象新增多的属性和方法。
1 | var createAnotherPerson = function(obj){ |
打印的person1如图:
6.寄生组合式继承
其实就是Child.prototype 继承了Parent.prototype,然后在Parent的构造函数内又可以添加自定义的属性。
1 | function inherit(subType, superType) {//这个方法做的事情其实就是让subType.prototype === superType.prototype |
打印的child如图:
es6编译成es5 super与extends实现
1 | class Parent{ |
编译结果:
1 | ; |
- 调用_createClass方法为Parent构造函数添加原型与静态属性
- 调用 _inherits(Child, _Parent)
1 | Child.prototype = Object.create(Parent.prototype, { |
也就是Child.prototype.__proto__ = Parent.prototype,Child.__proto__ = Parent
- 调用_createClass为Child构造函数添加原型与静态属性
- 创建Child实例
- 调用 _classCallCheck(this, Child),如果不是Child的实例就扔出错误
- 接着调用_possibleConstructorReturn(this, _getPrototypeOf(Child).call(this))
- 先进入_getPrototypeOf调用,得到Child的__proto__,也就是Parent
- 接着也就是调用Parent.call(this),也就是调用_classCallCheck(this, Parent)
- 调用_possibleConstructorReturn
- 进入_assertThisInitialized(self)调用,如果self等于undefined,扔出错误。
- 调用child.getChildName方法,也就是调用到下面这个
1 | _get(_getPrototypeOf(Child.prototype), "getParentName", this).call(this); |
最后进入
1 | return _get(target, property, receiver || target) |
得到Parent上的getParentName方法
总结
extends实现总的来说就是
Child.prototype.__proto__ = Parent.prototype
Child.__proto__ = Parent
super的实现是先获取了原型上的某个方法,再调用