javaScript的七种继承方式

46 阅读2分钟

原型链继承

子对象可以访问父对象原型链上的属性和方法,

对原型修改影响所有子对象

function Parent (){
  this.name = 'Parent';
}
Parent.prototype.sayHello = function(){
  console.log('hello')
}
function Child () {
  this.name = 'Child';
}
Child.prototype = new Parent();
let child = new Child();
child.sayHello();

构造函数继承

在子构造函数中调用父构造函数来实现,只能继承父构造函数的实例属性

无法访问父对象原型链上的属性和方法

function Parent (name){
  this.name = name;
}
function Child (name) {
  Parent.call(this,name)
}
let child = new Child('Child');

组合继承

继承了父构造函数的属性,又继承了父构造函数原型对象上的方法。

会调用两次父构造函数

function Parent (name){
  this.name = name; 
}
Parent.prototype.sayHello = function(){
  console.log('hello')
}
function Child (name) {
  Parent.call(this,name)
}
Child.prototype = new Parent('parent');
let child = new Child('Child');
child.sayHello();
console.log(child.name)

原型式继承

创建一个新对象,将其原型对象指向另一个已有的对象

可以实现属性和方法的继承,但是不能传递构造函数的参数

var Parent ={
  name:'Parent',
  sayHello: function() {
    console.log('Hello')
  }
}
var child = Object.create(parent);
console.log(child.name)
child.sayHello();

寄生式继承

在原型式继承的基础上,增强对象的功能。

难以重用

function createAnother(obj) {
  // 创建一个新对象
  let clone = Object.create(obj);
  // 增强对象的功能
  clone.sayHi = function() {
    console.log('Hi');
  };
  // 返回增强后的对象
  return clone;
}
​
let person = {
  name: 'John',
  age: 30
};
​
let anotherPerson = createAnother(person);
​
console.log(anotherPerson.name); 
anotherPerson.sayHi(); 

寄生组合式继承

只调用一次父类构造函数

// 通用版
function Parent(name) {
  this.name = name;
}
Parent.prototype.getName = function() {
  console.log(this.name);
};
function Child(name, age) {
  // 调用父类的构造函数
  Parent.call(this, name); 
  this.age = age;
}
function createObj(o) {
  // 目的是为了继承父类原型上的属性和方法,在不需要实例化父类构造函数的情况下,避免生成父类的实例,如new Parent()
  function F() {}
  F.prototype = o;
  // 创建一个空对象,该对象原型指向父类的原型对象
  return new F(); 
}
​
// 等同于 Child.prototype = Object.create(Parent.prototype)
Child.prototype = createObj(Parent.prototype); 
Child.prototype.constructor = Child;
​
let child = new Child("tom", 12);
child.getName(); // tom

class

class Parent {
  constructor(age) {
    this.age = age;
  }
  getName() {
    console.log(this.name);
  }
}
class Child extends Parent {
  constructor(name, age) {
    super(age);
    this.name = name;
  }
}

手写class类

function selfClass(Child, Parent) {
  // Object.create 第二个参数,给生成的对象定义属性和属性描述符/访问器描述符
  Child.prototype = Object.create(Parent.prototype, {
    // 子类继承父类原型上的属性和方法
    constructor: {
      enumerable: false,
      configurable: false,
      writable: true,
      value: Child
    }
  });
  // 继承父类的静态属性和静态方法
  Object.setPrototypeOf(Child, Parent);
}
​
// 测试
function Child() {
  this.name = 123;
}
function Parent() {}
// 设置父类的静态方法getInfo
Parent.getInfo = function() {
  console.log("info");
};
Parent.prototype.getName = function() {
  console.log(this.name);
};
selfClass(Child, Parent);
Child.getInfo(); // info
let tom = new Child();
tom.getName(); // 123