JS继承的6种方式及优缺点

参考文章:一文看懂 JS 继承

构造函数继承
优势
  • 可以定义私有属性方法

  • 子类传递参数给父类

劣势
  • 不能定义共享的属性方法

  • 共享的属性方法需要写在外面 失去了封装性

:chestnut:

let share = [1, 2, 3];

function log () {

  console.log(this.name);

}

function Parent (name, friends) {

  this.name = name;

  this.friends = friends;

  this.share = share;

  this.log = log;

}

function Child (name, friends, gender) {

  Parent.call(this, name, friends);

  this.gender = gender;

}

原型链继承

原型链模式需要手动重新绑定 constructor 而且不能定义私有变量

优势
  • 可以定义公有属性和方法
劣势
  • 无论是定义还是继承都需要手动修改 constructor

  • 封装性一般

  • 不能定义私有属性方法

  • 没办法向父类传递参数

:chestnut:

function Parent () { };

Parent.prototype = {

  constructor: Parent,// 需要手动绑定constructor

  name: 'oli',//不能定义私有属性 全部都是公有的

  friends: ['alice', 'troy'],// 方法和属性都是公有的 所有实例都引用这个

  log: function () {

    return this.name

  }

}

// 封装性一般

function Child () { };// 没办法向父类传递参数

Child.prototype = new Parent();// 使用new 操作符创建并重写prototype

console.log(Child.prototype.constructor);

Child.prototype.constructor = Child; // 每次继承都需要手动修改constructor

组合继承 原型链继承+构造函数继承
优势
  • 公有的写在原型

  • 私有的卸载构造函数

  • 可以向父类传递参数

劣势
  • 需要手动绑定constructor

  • 封装性一般

  • 重复调用父类性能损耗

:chestnut:


function Parent (name, friends) {

  // 私有的部分

  this.name = name;

  this.friends = friends;

}

Parent.prototype = {

  // 公有的写这里

  constructor: Parent,// 需要手动绑定

  share: [1, 2, 3],

  log: function () {

    return this.name;

  }

}

// 封装性一般

function Child (name, friends, gender) {

  Parent.call(this, name, friends); // 这里调用了一次Parent

  this.gender = gender;

}

Child.prototype = new Parent(); // 这里又调用了一次Parent

Child.prototype.constructor = Child;//需要手动修改constructor

原型式继承

原型式继承方法直接使用ES5object.create方法

object.create原理
  • 创建一个构造函数,构造函数的原型指向对象,

  • 调用 new 操作符创建实例,并返回这个实例,

  • 本质是一个浅拷贝

优点
  • 父类方法可以复用
缺点
  • 父类引用属性全部被共享

  • 子类不可传递参数给父类

:chestnut:


let parent = {

  name: 'parent',

  share: [1, 2, 3],// 父类的属性全部被子类共享

  log: function () {  // 父类的方法可以复用

    return this.name;

  }

}

let child = Object.create(parent);

寄生式继承

在原生式继承的基础上为子类增加属性和方法 二次封装

优势
  • 父类方法可以复用

  • 增加了别的属性和方法

劣势
  • 父类引用属性全部被共享

  • 子类不可传递参数给父类

:chestnut:


let parent = {

  name: 'parent',

  share: [1, 2, 3],

  log: function () {

    return this.name;

  }

}

function create (obj) {

  let cloneObj = Object.create(obj);

  cloneObj.print = function () { // 增加了一些属性和方法

    console.log(this.name)

  }

  return cloneObj;

}

let child = create(parent);

寄生组合式继承

杂糅了原型链式、构造函数式、组合式、原型式、寄生式而形成的一种方式:

主要是解决了组合继承的唯一缺点:多次调用Parent

优点:
  • 公有的写在原型

  • 私有的写在构造函数

  • 可以向父类传递参数

  • 不会重复调用父类

缺点
  • 需要手动绑定constructor

  • 需要调用额外的方法 封装性一般

:chestnut:


function Parent (name, friends) {

  this.name = name;

  this.friends = friends;

}

Parent.prototype = {

  constructor: Parent,//需要手动绑定constructor

  share: [1, 2, 3],

  log: function () {

    return this.name

  }

}

function Child (name, friends, gender) {

  Parent.call(this, name, friends);

  this.gender = gender;

}

function proto(child, parent) {

  let clonePrototype = Object.create(parent.prototype)

  child.prototype = clonePrototype

  child.prototype.constructor = child

}

proto(Child,Parent);

ES6 class

:chestnut:


class Parent {

    constructor(name, friends) { // 该属性在构造函数上,不共享

        this.name = name

        this.friends = friends

    }

    log() { // 该方法在原型上,共享

        return this

    }

}

Parent.prototype.share = [1, 2, 3] // 原型上的属性,共享

class Child extends Parent {

    constructor(name, friends, gender) {

        super(name, friends)

        this.gender = gender

    }

}

你可能感兴趣的:(JS继承的6种方式及优缺点)