手撸 JS 六大继承,看完包会!!🔥

699 阅读3分钟

手撸 JS 六大继承

前言

继承概念:利用原型让一个引用类型继承另一个引用类型的属性和方法

函数都有一个 prototype 属性,该属性指向一个对象(这个对象指的是函数的原型对象)

举一个生活中的例子:先定义一个类(Class)叫汽车,汽车的属性包括颜色、轮胎、品牌、速度、排气量等,由汽车这个类可以派生出“轿车”和“货车”两个类,那么可以在汽车的基础属性上,为轿车添加一个后备厢、给货车添加一个大货箱。这样轿车和货车就是不一样的,但是二者都属于汽车这个类,这样从这个例子中就能详细说明汽车、轿车以及卡车之间的继承关系。 继承可以使得子类别具有父类的各种方法和属性,比如上面的例子中“轿车” 和 “货车” 分别继承了汽车的属性,而不需要再次在“轿车”中定义汽车已经有的属性。在“轿车”继承“汽车”的同时,也可以重新定义汽车的某些属性,并重写或覆盖某些属性和方法,使其获得与“汽车”这个父类不同的属性和方法。

1. 原型链继承

核心代码:SubType.prototype = new SuperType()

SuperType.prototype.getSuperValue = function() {
  return this.property
}

// 父类
function SuperType() {
  this.property = true
  this.name = 'aa'
}

// 子类
function SubType() {
  this.subproperty = false
}

`核心原理`: 将子类的原型赋值为父类的实例对象
SubType.prototype = new SuperType() // { property: true, __proto__: SuperType.prototype }

// SubType.prototype.getSuperValue = function() {
//   return this.subproperty
// }

var instance = new SubType('xxx')
// instance:
// { 
//   subproperty: false, 
//   __proto__: { 
//     property: true, 
//     __proto__: SuperType.prototype 
//   }
// }
instance.getSuperValue() // true

var instance2 = new SubType()

1. 原型链继承 缺点:

  • 原型实际上会变成另一个类型的实例,并且这个实例中的属性会被所有的子类实例所共享(改变了其中一个属性,则其他实例化对象上的属性也会对应发生改变)
  • 在创建子类型的实例时,做不到向超类型的构造函数传参

2. 构造函数继承(经典继承)

核心代码:SuperType.call(this, name)

function SuperType(name) {
  this.colors = ['red', 'green', 'blue']
  this.people = ['a', 'b', 'c']
}

function SubType(name) {
  SuperType.call(this, name)
}

var instance1 = new SubType()
instance1.colors.push('pink')
console.log(instance1.colors); // ['red', 'green', 'blue']

var instance2 = new SubType('小明')
console.log(instance2.colors);

2. 构造函数继承(经典继承)优点:

  • 解决了原型链继承的两个缺点

构造函数继承(经典继承)缺点:

  • 子类实例无法继承到超类构造函数原型上的属性和方法
  • 所有的属性和方法都只能写在构造函数内部,降低了代码的复用性

3. 组合继承(伪经典继承)

核心代码:

  • SuperType.call(this, name)
  • SubType.prototype = new SuperType()
  • SubType.prototype.constructor = SubType
SuperType.prototype.sayName = function() {
  console.log(this.name);
}
function SuperType(name) {
  this.name = name
  this.colors = ['red', 'green', 'blue']
}

function SubType(name, age) {
  SuperType.call(this, name)
  this.age = age
}
SubType.prototype = new SuperType()
SubType.prototype.constructor = SubType
SubType.prototype.sayAge = function() {
  console.log(this.age);
}

var instance1 = new SubType('小南', 20)
// console.log(instance1.colors); // ['red', 'green', 'blue']
instance1.sayName()
instance1.sayAge()

var instance2 = new SubType('小赖', 22)
instance2.sayName()
instance2.sayAge()

console.log(instance1 instanceof SubType);

3. 组合继承(伪经典继承)缺点:

  • 超类构造函数无论何时,都要被调用两次

4. 原型式继承(单纯的对象之间继承可以胜任)

核心代码:var person1 = Object.create(person)

// 原型式继承

// function object(o) {
//   function F() {}
//   F.prototype = o
//   return new F()
// }

// -----------------------------

var person = {
  name: '小红',
  colors: ['red', 'green', 'blue']
}

var person1 = Object.create(person, {
  name: {
    value: '小明'
  }
})

var person2 = Object.create(person, {
  name: {
    value: '小王'
  }
})

person1.colors.push('pink')
console.log(person1.name);  // 小明
console.log(person2.name);  // 小王
console.log(person1.colors);  // [ 'red', 'green', 'blue', 'pink' ]
console.log(person2.colors);  // [ 'red', 'green', 'blue', 'pink' ]

4. 原型式继承 缺点:

  • 包含引用类型值的属性始终会共享

5. 寄生式继承

核心代码:var clone = Object.create(original) 函数 createPerson

//  寄生式继承
function createPerson(original) {
  var clone = Object.create(original)
  clone.sayGood = function() {
    console.log('hello');
  }
  return clone
}


let obj = {
  name: 'aaa'
}

let obj2 = createPerson(obj)

5. 寄生式继承 缺点:

  • 做不到函数的复用`

6. 寄生组合式继承

核心代码:

  • SuperType.call(this, name)
  • SubType.prototype = Object.create(SuperType.prototype)
  • SubType.prototype.constructor = SubType
// 寄生组合式继承
SuperType.prototype.sayName = function() {
  console.log(this.name);
}
function SuperType(name) {
  this.name = name
  this.colors = ['red', 'green', 'blue']
}


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() {
  console.log(this.age);
}


var instance1 = new SubType('小南', 20)
instance1.colors.push('pink')
instance1.sayName()  // 小南
instance1.sayAge()  // 20
console.log(instance1.colors);  // [ 'red', 'green', 'blue', 'pink' ]

var instance2 = new SubType('小赖', 22)
instance2.sayName()  // 小赖
instance2.sayAge()  // 22
console.log(instance2.colors);  // [ 'red', 'green', 'blue' ]

目前来说应用最多的,相对而言,没有更好的解决方案,最优:寄生式组合继承

小编自制了一个 登录注册验证码,npm i 开箱即用,可以了解一下:给个 star 支持一下,谢谢~

地址:github.com/SmallFishCo…