阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 继承实现方式

继承实现方式

作者:陈川 阅读数:3369人阅读 分类: JavaScript

继承的概念

继承是面向对象编程的核心概念之一,允许一个对象获取另一个对象的属性和方法。在JavaScript中,继承主要通过原型链实现,ES6之后也可以通过class语法糖实现更直观的继承方式。

原型链继承

原型链继承是最基本的继承方式,通过将子类的原型指向父类的实例来实现继承。

function Parent() {
  this.name = 'parent';
  this.colors = ['red', 'blue'];
}

Parent.prototype.sayName = function() {
  console.log(this.name);
};

function Child() {
  this.age = 10;
}

// 关键步骤:将Child的原型指向Parent的实例
Child.prototype = new Parent();

const child1 = new Child();
child1.sayName(); // 输出: parent
console.log(child1.age); // 输出: 10

这种方式的缺点是:

  1. 所有子类实例共享父类实例的引用属性
  2. 无法向父类构造函数传参

构造函数继承

构造函数继承通过在子类构造函数中调用父类构造函数来实现。

function Parent(name) {
  this.name = name;
  this.colors = ['red', 'blue'];
}

function Child(name, age) {
  Parent.call(this, name); // 关键步骤:调用父类构造函数
  this.age = age;
}

const child1 = new Child('Tom', 10);
console.log(child1.name); // 输出: Tom
console.log(child1.age); // 输出: 10

优点:

  1. 解决了原型链继承中引用属性共享的问题
  2. 可以向父类构造函数传参

缺点:

  1. 无法继承父类原型上的方法
  2. 每次创建实例都要调用父类构造函数

组合继承

组合继承结合了原型链继承和构造函数继承的优点。

function Parent(name) {
  this.name = name;
  this.colors = ['red', 'blue'];
}

Parent.prototype.sayName = function() {
  console.log(this.name);
};

function Child(name, age) {
  Parent.call(this, name); // 第二次调用Parent
  this.age = age;
}

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

const child1 = new Child('Tom', 10);
child1.sayName(); // 输出: Tom
console.log(child1.age); // 输出: 10

优点:

  1. 可以继承父类实例属性和原型属性
  2. 可以传参
  3. 引用属性不共享

缺点:

  1. 父类构造函数被调用了两次

原型式继承

原型式继承基于已有对象创建新对象,类似于Object.create()的实现。

function createObject(o) {
  function F() {}
  F.prototype = o;
  return new F();
}

const parent = {
  name: 'parent',
  colors: ['red', 'blue'],
  sayName: function() {
    console.log(this.name);
  }
};

const child = createObject(parent);
child.name = 'child';
child.sayName(); // 输出: child

ES5中可以直接使用Object.create()实现同样的功能。

寄生式继承

寄生式继承在原型式继承的基础上增强对象。

function createAnother(original) {
  const clone = Object.create(original);
  clone.sayHi = function() {
    console.log('hi');
  };
  return clone;
}

const parent = {
  name: 'parent',
  colors: ['red', 'blue']
};

const child = createAnother(parent);
child.sayHi(); // 输出: hi

寄生组合式继承

寄生组合式继承是目前最理想的继承方式,解决了组合继承调用两次构造函数的问题。

function inheritPrototype(child, parent) {
  const prototype = Object.create(parent.prototype);
  prototype.constructor = child;
  child.prototype = prototype;
}

function Parent(name) {
  this.name = name;
  this.colors = ['red', 'blue'];
}

Parent.prototype.sayName = function() {
  console.log(this.name);
};

function Child(name, age) {
  Parent.call(this, name);
  this.age = age;
}

inheritPrototype(Child, Parent);

const child1 = new Child('Tom', 10);
child1.sayName(); // 输出: Tom
console.log(child1.age); // 输出: 10

ES6类继承

ES6引入了class语法糖,使继承更加直观。

class Parent {
  constructor(name) {
    this.name = name;
    this.colors = ['red', 'blue'];
  }
  
  sayName() {
    console.log(this.name);
  }
}

class Child extends Parent {
  constructor(name, age) {
    super(name); // 调用父类构造函数
    this.age = age;
  }
  
  sayAge() {
    console.log(this.age);
  }
}

const child1 = new Child('Tom', 10);
child1.sayName(); // 输出: Tom
child1.sayAge(); // 输出: 10

多重继承的实现

JavaScript本身不支持多重继承,但可以通过混入(Mixin)模式模拟。

class A {
  methodA() {
    console.log('method A');
  }
}

class B {
  methodB() {
    console.log('method B');
  }
}

class C {
  constructor() {
    Object.assign(this, new A());
    Object.assign(this, new B());
  }
  
  methodC() {
    console.log('method C');
  }
}

const c = new C();
c.methodA(); // 输出: method A
c.methodB(); // 输出: method B
c.methodC(); // 输出: method C

继承与性能考虑

原型链查找会影响性能,过深的原型链会导致查找时间增加。在性能敏感的场景下,可以考虑将常用方法直接定义在对象上。

function createOptimizedObject() {
  const obj = {};
  obj.method1 = function() { /* ... */ };
  obj.method2 = function() { /* ... */ };
  return obj;
}

继承与设计模式

继承在多种设计模式中都有应用,如模板方法模式、装饰器模式等。

// 模板方法模式示例
class AbstractClass {
  templateMethod() {
    this.operation1();
    this.operation2();
  }
  
  operation1() {
    throw new Error('必须实现operation1');
  }
  
  operation2() {
    throw new Error('必须实现operation2');
  }
}

class ConcreteClass extends AbstractClass {
  operation1() {
    console.log('具体操作1');
  }
  
  operation2() {
    console.log('具体操作2');
  }
}

const instance = new ConcreteClass();
instance.templateMethod();

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:constructor属性

下一篇:对象拷贝与比较

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌