# 继承实现

# 原型链继承

通过将父类的实例 赋值给 子类的prototype属性值 ,继承父类的属性和方法

缺点:

  • 只复制了方法,并未复制属性,造成子类实例共享属性,造成实例间的属性会相互影响(引用类型取值)
  • 在创建子类实例时,不能向超类的构造函数中传递参数
function SuperType() {
  this.property = true;
}
SuperType.prototype.getSuperValue = function() {
  return this.property;
}
function SubType() {
  this.property = false;
}
//继承了SuperType
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType

var instance = new SubType();
console.log(instance.getSuperValue());//false
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 构造函数继承

通过在子类构造函数的内部调用父类构造函数,实现继承

  • 优点:能向超类构造函数中传递参数
  • 缺点:
    • 没有共享同一个方法,无法进行函数复用
    • 并且instance1 instanceof SuperType为false,无法通过原型链判断对象是否属于父类
function SuperType() {
  this.colors = ["red","blue","green"];
}
function SubType() {
  SuperType.call(this);//继承了SuperType
}
var instance1 = new SubType();
instance1.colors.push("black");
console.log(instance1.colors);//"red","blue","green","black"
var instance2 = new SubType();
console.log(instance2.colors);//"red","blue","green"
1
2
3
4
5
6
7
8
9
10
11

# 组合继承(伪经典继承)

结合 原型继承继承方法构造继承继承属性 ,实现继承

思路:使用原型链实现对原型属性与方法的继承,通过构造函数实现对实例属性的继承

缺点:父类构造函数被调用两次,子类实例的属性存在两份

function SuperType(name) {
  this.name = name;
  this.colors = ["red","blue","green"];
}
SuperType.prototype.sayName = function() {
  console.log(this.name);
}
function SubType(name, age) {
  SuperType.call(this,name); //第二次调用SuperType,屏蔽了原型中的两个同名属性
  this.age = age;
}
//继承方法
SubType.prototype = new SuperType(); // 第一次调用
Subtype.prototype.constructor = Subtype;
Subtype.prototype.sayAge = function() {
  console.log(this.age);
}

var instance1 = new SubType("EvanChen",18);
instance1.colors.push("black");
consol.log(instance1.colors);//"red","blue","green","black"
instance1.sayName();//"EvanChen"
instance1.sayAge();//18
var instance2 = new SubType("EvanChen666",20);
console.log(instance2.colors);//"red","blue","green"
instance2.sayName();//"EvanChen666"
instance2.sayAge();//20
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
27

# 原型式继承

借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型

  • 缺点:传入的引用类型值,并不属于o所有,也同时属于之后新建的实例
// Object.create()的polyfill
// 实际上就相当于创建了 o 对象的两个副本
Object.create = Object.create || function (o) {
  function F() {}
  F.prototype = o
  return new F()
}

1
2
3
4
5
6
7
8

# Object.create()的出现

ECMAScript 5 通过新增的Object.create()规范化了原型式继承

# 寄生式继承

与原型式继承紧密相关,思路与寄生构造函数与工厂模式类似,即创建一个用于仅用于封装继承过程的函数,该函数在在内部以某种方式来增强对象

  • 缺点:使用寄生式继承来为对象添加函数,会由于不能做到函数服用而降低效率,这一点与构造函数模式类似
function createAnother(original) {
  var clone = Object.create(original)
  clone.sayHi = function() {
    alert('hi')
  }
  return clone
}
1
2
3
4
5
6
7

# 寄生组合式继承

通过借用构造函数来继承属性,通过原型链的混成形式来继承方法

子类都有各自的实例不会相互影响,且共享了父类的方法

function SuperType(name) {
  this.name = name
  this.colors = ["red","blue","green"];
}
SuperType.prototype.getColors = function() {
  return this.colors
}
function SubType(name, age) {
  SuperType.call(this, name);
  this.age = age
}

SubType.prototype = Object.create(SuperType.prototype)// 不必调用超类构造函数,只需要副本即可
SubType.prototype.constructor = SubType
SubType.prototype.sayAge = function() {
  alert(this.age)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# ES6实现继承

通过extends实现,效果与寄生继承一致