29.js继承的几种方式

94 阅读2分钟

继承也是js八股文中常考的问题,本文主要介绍了js中实现继承的五种方法,帮助大家更好的理解和使用JavaScript,感兴趣的朋友可以了解下

原型链继承

原理就是子类的原型对象指向父类的实例

 // 父类
 function Parent() {
   this.name = '父类';
   this.introduce = function () {
     console.log('my name is' + this.name);
   };
 }
 // 子类
 function Child() {
   this.childname = '子类';
 }
 // 核心代码:
 Child.prototype = new Parent();

缺点

  • 父类的引用属性会被所有子类实例共享,就是多个子类实例对父类引用类型的操作会被纂改,无法保持子类实例的个性
  • 子类构建实例时不能向父类传递参数

构造函数继承

在子类的构造函数中,执行父类的构造函数,并且为其绑定子类的this.
这是所有继承中唯一一个不涉及到prototype的继承

// 父类
function Parent() {
  this.name = ['父类']
  this.introduce = function () {
    console.log("父类上的introduce方法")
  }
}
Parent.prototype.sayhi = function () {
  console.log('父类原型上的sayhi方法');
}
// 子类
function Child() {
  this.childname = ['子类']
  Parent.call(this)

缺点

  • 父类的方法不能复用,子类实例的方法每次都是单独创建的
  • 继承不到父类原型上的属性和方法

组合继承

构造函数和原型链2中继承组合使用.

// 父类
function Parent() {
  this.name = ['父类']
  this.introduce = function () {
    console.log("父类上的introduce方法")
  }
}
Parent.prototype.sayhi = function () {
  console.log('父类原型上的sayhi方法');
}
// 子类
function Child() {
  this.childname = ['子类']
  Parent.call(this) // 第二次调用Parent
}

Child.prototype = new Parent() // 第一次调用Parent

缺点

  • 调用了2次父类,原型链和构造函数都调用了父类,从而覆盖了子类上的同名参数,造成性能浪费

原型式继承

利用一个空对象作为中介、将某个对象直接赋值给空对象构造函数的原型,其实就是使用Object.create() ECMAScript 5 通过新增 Object.create()方法规范化了原型式继承。这个方法接收两个参数:一 个用作新对象原型的对象和(可选的)一个为新对象定义额外属性的对象。在传入一个参数的情况下, Object.create()与 object()方法的行为相同。——《JAVASCript高级编程》

var son=object( Person); var son = Object.create(Person);

缺点:

  • 跟原型链继承一样,多个子类实例的引用类型属性指向相同,可能会纂改。

寄生组合式继承

 // 父类
function Parent() {
  this.name = ['父类']
  this.introduce = function () {
    console.log("父类上的introduce方法")
  }
}
Parent.prototype.sayhi = function () {
  console.log('父类原型上的sayhi方法');
}
// 子类
function Child() {
  this.childname = ['子类']
  Parent.call(this) // 核心代码
}
Child.prototype = Object.create(Parent.prototype) // 核心代码

组合继承有一个会两次调用父类的构造函数造成浪费的缺点,寄生组合继承就可以解决这个问题。

ES6 Class extends

      class Parent {}
      class Son extends Parent {
        constructor() {
          super();
        }
      }

他是一个基于ES6Class和extends的语法糖,实现原理是改变其原型链

      class Parent {}
      class Son {}
      Object.setPrototypeOf = function (obj, proto) {
        obj.__proto__ = proto;
        return obj;
      };
      // B 的实例继承 A 的实例
      Object.setPrototypeOf(Son.prototype, Parent.prototype);

      // B 继承 A 的静态属性
      Object.setPrototypeOf(Son, Parent);