JavaScript继承

JavaScript继承

谈OOP怎么可能不提继承呢😄!在原型链中,已经介绍,OOP语言支持两种继承方式:接口继承实现继承。接口继承只继承方法签名,而实现继承则继承实际的方法。 在 ECMAScript 中无法实现接口继承。ECMAScript 只支持实现继承,而且其实现继承主要是依靠原型链 来实现的。

《JavaScript高级程序设计(4th)》中介绍了介绍原型链、构造函数继承、组合继承、原型式继承、寄生式继承、寄生组合式继承等6种方法。

但是通过细心研读可以发现,书中真正推荐使用继承方法只有两个:组合继承(combination inheritance)或寄生组合式继承,以及class关键字

(寄生)组合继承

组合继承(combination inheritance)又称伪经典继承(pseudo classical inheritance),它使用原型链实现对原型属性和方法的继承,而通过构造函数实现对实例属性的继承。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function Parent(name1){
this.name1 = name1;
}
Parent.prototype.pMethod = function(){
console.log(this.name1);
}

function Child(name2, name1){
// 调用构造函数
// inherit instance properties
Parent.call(this, name1) ;
this.name2 = name2;
}

const empty = function(){}
// 调用构造函数
// inherit instance properties
empty.prototype = Parent.prototype;
// inherit methods
Child.prototype = new empty();
// Child.prototype.__proto__ = Parent.prototype ;


Child.prototype.cMethod = function(){
console.log(this.name2);
}
  • 共用方法写在 Parent.prototype 中,通过原型链实现继承
  • 非共用属性(name1)放在构造函数中,让每一个实例都有自己的副本
  • 组合继承方式调用了两次构造函数,一次是创建子类 Child 的原型 prototype 时,一次是在子类的构造函数中借用构造函数时。这样可能得到一些没用的实例属性,同时复杂的构造函数可能会影像性能。

为了优化这个过程,就出现了寄生组合继承模式:把new关键字换成 Object.create() 方法即可

1
2
3
4
// Child.prototype = new Parent();
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
Child.prototype.childMethod = function(){};

基于 class 关键字继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Parent{
constructor(name1){
this.name1 = name1;
}
pMethod(){
console.log(this.name1);
}
}
class Child extends Parent{
constructor(name2, name1){
// inherit instance properties
super(name1) // 调用parent构造函数
this.name2 = name2;
}
cMethod(){
console.log(this.name2);
}
}

派生类的方法可以通过 super 关键字引用它们的原型。这个关键字只能在派生类中使用,而且仅
限于类构造函数、实例方法和静态方法内部。在类构造函数中使用 super 可以调用父类构造函数。

不能在调用 super 之前使用this,否则会抛出 ReferenceError

总结:重要继承模式

  • 原型链继承 : 得到方法
    1
    2
    3
    4
    5
    6
    function Parent(){};
    Parent.prototype.test = function(){};
    function Child(){};
    Child.prototype = new Parent(); // 子类型的原型指向父类型实例
    Child.prototype.constructor = Child
    var child = new Child(); //有test()
  • 借用构造函数 : inherit instance properties
    1
    2
    3
    4
    5
    6
    function Parent(xxx){this.xxx = xxx}
    Parent.prototype.test = function(){};
    function Child(xxx,yyy){
    Parent.call(this, xxx);//借用构造函数 this.Parent(xxx)
    }
    var child = new Child('a', 'b'); //child.xxx为'a', 但child没有test()
  • 组合
    1
    2
    3
    4
    5
    6
    7
    function Parent(xxx){this.xxx = xxx}
    Parent.prototype.test = function(){};
    function Child(xxx,yyy){
    Parent.call(this, xxx);//借用构造函数 this.Parent(xxx)
    }
    Child.prototype = new Parent(); //得到test()
    var child = new Child(); //child.xxx为'a', 也有test()

版权声明:本文作者为「Andy8421」.本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!