JavaScript 的继承方式

34 阅读2分钟

JavaScript 的继承方式及代码示例

JavaScript 是一种基于原型的语言,它提供了多种实现继承的方式。以下是主要的几种继承方式及其代码示例:

1. 原型链继承

javascript

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

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

function Child() {
  this.childName = 'Child';
}

// 继承 Parent
Child.prototype = new Parent();

const child1 = new Child();
console.log(child1.getName()); // "Parent"
console.log(child1.childName); // "Child"

// 问题:引用类型的属性会被所有实例共享
const child2 = new Child();
child1.colors.push('black');
console.log(child2.colors); // ["red", "blue", "green", "black"]

2. 构造函数继承(经典继承)

javascript

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

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

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

const child1 = new Child('Tom', 18);
console.log(child1.name); // "Tom"
console.log(child1.age); // 18

// 引用类型属性不会被共享
const child2 = new Child('Jerry', 20);
child1.colors.push('black');
console.log(child2.colors); // ["red", "blue", "green"]

// 问题:无法继承父类原型上的方法
console.log(child1.getName); // undefined

3. 组合继承(原型链 + 构造函数)

javascript

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

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

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

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

const child1 = new Child('Tom', 18);
console.log(child1.getName()); // "Tom"
console.log(child1.age); // 18

const child2 = new Child('Jerry', 20);
child1.colors.push('black');
console.log(child2.colors); // ["red", "blue", "green"]

4. 原型式继承

javascript

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

const person = {
  name: 'Person',
  colors: ['red', 'blue', 'green']
};

const person1 = createObj(person);
person1.name = 'Tom';
person1.colors.push('black');

const person2 = createObj(person);
console.log(person2.name); // "Person"
console.log(person2.colors); // ["red", "blue", "green", "black"]

5. 寄生式继承

javascript

function createAnother(original) {
  const clone = Object.create(original); // 通过调用函数创建一个新对象
  clone.sayHi = function() { // 以某种方式增强这个对象
    console.log('Hi');
  };
  return clone;
}

const person = {
  name: 'Person',
  colors: ['red', 'blue', 'green']
};

const anotherPerson = createAnother(person);
anotherPerson.sayHi(); // "Hi"

6. 寄生组合式继承(最理想的方式)

javascript

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', 'green'];
}

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

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

// 将父类原型赋值给子类
inheritPrototype(Child, Parent);

// 添加子类方法
Child.prototype.getAge = function() {
  return this.age;
};

const child1 = new Child('Tom', 18);
console.log(child1.getName()); // "Tom"
console.log(child1.getAge()); // 18

7. ES6 Class 继承

javascript

class Parent {
  constructor(name) {
    this.name = name;
    this.colors = ['red', 'blue', 'green'];
  }
  
  getName() {
    return this.name;
  }
}

class Child extends Parent {
  constructor(name, age) {
    super(name); // 调用父类的constructor
    this.age = age;
  }
  
  getAge() {
    return this.age;
  }
}

const child1 = new Child('Tom', 18);
console.log(child1.getName()); // "Tom"
console.log(child1.getAge()); // 18

const child2 = new Child('Jerry', 20);
child1.colors.push('black');
console.log(child2.colors); // ["red", "blue", "green"]

总结

  1. 原型链继承:简单但引用属性共享
  2. 构造函数继承:解决属性共享问题但无法继承原型方法
  3. 组合继承:结合前两者优点但调用两次父类构造函数
  4. 原型式继承:类似Object.create()的浅复制
  5. 寄生式继承:增强对象但方法不能复用
  6. 寄生组合式继承:最理想的继承方式
  7. ES6 Class:语法糖,底层基于寄生组合式继承

现代开发中推荐使用ES6的class语法,它简洁且易于理解,底层实现也是最优的继承方式。

相关文章: Typescript中的继承示例