JavaScript类和继承

107 阅读2分钟

说明:本文仅是笔记

一、原型链继承

// 将父类的实例赋给子类的原型
function superType() {
  this.property = true
}
superType.prototype.getSuperType = function() {
  return this.property
}

function subType() {}
// 创建父类的实例赋给子类原型
subType.prototype = new superType()

var insance = new subType()
console.log(insance.getSuperType()); // true

// instance.__proto__ = subType.prototype -> subType.prototype.__proto__ = superType.prototype
// 缺点:多个实例共享引用类型,当引用类型发生改变,所有实例都有受到影响

二、借用构造函数继承

// 使用父类构造函数增强子类实例
function superType() {
  this.arr = [1,2,3]
}
function subType() {
  superType.call(this)
}
const instance1 = new subType()
instance1.arr.push(4)
console.log(instance1.arr); // [ 1, 2, 3, 4 ]

const instance2 = new subType()
console.log(instance2.arr); // [ 1, 2, 3 ]

// 子类的每个实例都会将父类的属性复制一份,无法实现复用
// 不能继承父类原型的方法和属性

三、组合继承

// 组合上面两种方法就是组合继承,原型链继承父类原型的属性和方法
// 构造函数实现对父类内部属性和方法的继承
function superType() {
  this.superName = 'superName'
}
superType.prototype.getSuperName = function() {
  return this.superName
}
function subType(name,age) {
  // 子类创建实例时再次调用superType
  superType.call(this)
  this.name = name
  this.age = age
}
// 第一次调用superType
subType.prototype = new superType()
subType.prototype.constructor = subType
const instance = new subType('XiaoMing',12)
console.log(instance.age);    // 12
console.log(instance.name);   // XiaoMing
console.log(instance.getSuperName()); // superName
// 子类实例中会存有两份父类内部的属性和方法(不包括原型上的属性和方法)

四、原型式继承

// 利用空对象作为中介 将对象复制给空对象构造函数的原型
function object(obj) {
  function F() {}
  F.prototype = obj
  return new F()
}
var person = {
  arrs: []
}

var instance1 = object(person)
instance1.arrs.push(1)
var instance2 = object(person)
instance2.arrs.push(2)

console.log(person.arrs); // [ 1, 2 ]

// 引用类型被多个实例共享,发生改变会影响所有实例
// 不能传递参数
// 存在Object.create()方法可以替代上面的object函数

五、寄生式继承

// 在原型式继承的基础上 增强对象
function object(obj) {
  function F() {}
  F.prototype = obj
  return new F()
}
function create(original) {
  var clone = object(original)
  clone.sayHi = function() {
    console.log('Hi');
  }
  return clone
}

var person = {
  name: 'XiaoMing'
}
var instance1 = create(person)
instance1.sayHi()             // Hi
console.log(instance1.name);  // XiaoMing

六、寄生式组合继承

// 结合借用构造函数传递参数和寄生模式实现原型链继承
// 相对于组合继承 子类中对父类内部的变量和函数只继承一次
// 这是最成熟的方法
function inheritProperty(subType, superType) {
  // prototype.__proto__ = superType.prototype
  var prototype = Object.create(superType.prototype)
  prototype.constructor = subType
  subType.prototype = prototype
}
function superType() {
  this.superName = 'superName'
}
superType.prototype.getSuperName = function() {
  return this.superName
}
function subType(name) {
  superType.call(this)
  this.subName = name
}

// 将父类原型指向子类
inheritProperty(subType, superType)
// 新增子类原型属性
subType.prototype.getSubName = function() {
  return this.subName
}

let instance = new subType('XiaoMing')
console.log(instance.getSuperName())  // superName
console.log(instance.getSubName())    // XiaoMing

七、ES6继承extends

class Rectangle {
  constructor(height,width) {
    this.height = height
    this.width = width
    this.name = 'Rectangle'
  }
  getArea() {
    return this.height * this.width
  }
}

class Square extends Rectangle {
  constructor(length) {
    super(length, length)
    // 子类使用this前需要先调用super()
    this.name = 'Square'
  }
}

let instance = new Square(40)
console.log(instance.getArea()); // 1600
console.log(instance.name);      // Square