JavaScript继承的方式有哪些?

JavaScript的继承机制是基于原型的,这为代码复用提供了多种模式。从早期的原型链继承到现代的ES6类语法,每种方式都有其适用场景和理解成本。了解这些模式对于设计和构建可扩展的应用程序结构至关重要。

原型链继承

这是最基本的继承方式,通过将子类的原型设置为父类的实例来实现。子类实例可以访问父类原型上定义的方法和属性。

function Parent() {
  this.name = 'Parent';
}
Parent.prototype.sayName = function() {
  return this.name;
};

function Child() {}
Child.prototype = new Parent();

const instance = new Child();
console.log(instance.sayName());

这种方式存在明显问题:所有子类实例共享同一个父类实例的引用属性。修改一个实例的引用属性(如数组)会影响到所有其他实例。

构造函数继承

为了解决原型链继承中引用属性共享的问题,可以在子类构造函数内部调用父类构造函数,从而为每个子类实例创建独立的属性副本。

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

const c1 = new Child('c1');
c1.colors.push('blue');
const c2 = new Child('c2');
console.log(c2.colors); // ['red']

这种方法虽然解决了属性独立的问题,但父类原型上定义的方法无法被子类实例访问到。

组合继承

组合继承结合了原型链和构造函数的优点,是最常用的经典继承模式。它使用构造函数继承属性,使用原型链继承方法。

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

function Child(name, age) {
  Parent.call(this, name);
  this.age = age;
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
Child.prototype.sayAge = function() {
  return this.age;
};

这种方式既保证了实例属性的独立性,又能让方法被复用。缺点是父类构造函数被调用了两次,可能会存在一些效率问题。

寄生组合式继承

这是一种更高效的继承方式,被视为引用类型最理想的继承范式。它通过一个空函数作为中介来继承父类的原型,避免了不必要的父类构造函数调用。

function inherit(Child, Parent) {
  const F = function() {};
  F.prototype = Parent.prototype;
  Child.prototype = new F();
  Child.prototype.constructor = Child;
}

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

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

ES6的Object.create()方法让这种实现变得更简洁。

ES6的class继承

ES6引入了基于类的语法,它本质上是上述原型继承的语法糖,但写法更清晰、更接近传统面向对象语言。

class Parent {
  constructor(name) {
    this.name = name;
  }
  sayName() {
    return this.name;
  }
}

class Child extends Parent {
  constructor(name, age) {
    super(name);
    this.age = age;
  }
  sayAge() {
    return this.age;
  }
}

extends关键字用于继承,super用于调用父类构造函数。这是现代JavaScript项目中最推荐使用的继承方式,它内部的工作原理依然是寄生组合式继承。

在实践中,对于新项目应优先使用ES6的class语法,它的意图明确且语法简洁。理解其背后的原型机制,有助于你更深入地调试和理解代码的行为。

© 版权声明
THE END
喜欢就支持一下吧
点赞6 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容