白话理解
- JavaScript基于原型链的继承,访问一个对象的属性时,如果找不到,则会顺着原型链向上层查找,以此类推,直到找不到为止
- 每个构造器都有一个
prototype
属性,代表该构造函数的原型对象 prototype
有个constructor
属性,指向它的构造函数,构造函数的constructor
指向自身- 实例化对象有个
__proto__
,指向它的原型prototype
- 不管哪种继承方式,
prototype
上的属性都是共享的,所以原型链上最好是增加的是方法,基本属性放到构造函数中,除非你确定你的基本属性是需要共享所有实例对象的
继承的几种方式
构造函数实现继承
- 只能继承构造函数的属性,无法继承原型属性
- 每个新实例都有父类构造函数的副本
- 每个实例都是重新实例化构造函数,不存在共享属性
- 可以通过
Parent.call(this,params)
传递参数到父类构造函数
1 | function Person() { |
原型链继承
- 所有实例共享父类实例属性,引用属性被修改时,所有都会被改
- 可以获得父构造函数以及原型属性
- 无法像父类传参
- 原型链继承时,当原型链属性修改,其他实例化的对象也会修改
1 | function Person() { |
组合继承
- 构造函数继承+
prototype
实例对象继承组合继承 - 构造函数继承可传参
- 实例对象原型链继承,保证属性是每个对象独有的
- 但是会造成两次调用父类构造函数
1 | function Person(name) { |
寄生继承
- 可以将最开始的对象扩展后,返回被继承
- 通原型链继承一样,此时无法获取到构造函数属性
- 寄生继承直接指向父类的
prototype
,所以不会重复调用父类的情况
1 | function Person() { |
寄生组合继承
- 构造函数继承+寄生继承
- 构造函数继承调用父类一次,寄生继承不在调用父类,通过直接委托prototype,所以解决了组合继承两次调用父类的情况
1 | function Person() { |