继承
1. 原型链继承
核心思想:
- 通过将子类的原型指向父类的实例,实现继承。 
- 子类可以访问父类原型上的属性和方法。 
代码示例:
function Parent() {
  this.name = "Parent";
}
Parent.prototype.sayName = function () {
  console.log(this.name);
};
function Child() {}
Child.prototype = new Parent(); // 原型链继承
const child = new Child();
child.sayName(); // 输出: Parent优点:
- 简单易用,直接利用原型链特性。 
缺点:
- 所有子类实例共享父类实例的引用属性(如数组、对象),容易造成数据污染。 
- 无法向父类构造函数传参。 
记忆技巧:
- 原型链:想象一条链子,子类通过 - prototype连接到父类的实例。
- 共享问题:记住“共享”是优点也是缺点,适合方法继承,不适合属性继承。 
2. 借用构造函数继承
核心思想:
- 在子类构造函数中调用父类构造函数,通过 - call或- apply实现属性继承。
- 解决了原型链继承中引用属性共享的问题。 
代码示例:
function Parent(name) {
  this.name = name;
  this.colors = ["red", "blue"];
}
function Child(name) {
  Parent.call(this, name); // 借用构造函数继承
}
const child1 = new Child("Child1");
child1.colors.push("green");
console.log(child1.colors); // 输出: ['red', 'blue', 'green']
const child2 = new Child("Child2");
console.log(child2.colors); // 输出: ['red', 'blue']优点:
- 解决了引用属性共享的问题。 
- 可以向父类构造函数传参。 
缺点:
- 无法继承父类原型上的方法。 
- 方法都在构造函数中定义,无法复用。 
记忆技巧:
- 借用:想象子类“借用”了父类的构造函数来初始化自己的属性。 
- 无法复用:记住方法无法复用,每次创建实例都会重新定义方法。 
3. 组合继承
核心思想:
- 结合原型链继承和借用构造函数继承。 
- 使用借用构造函数继承属性,使用原型链继承方法。 
代码示例:
function Parent(name) {
  this.name = name;
  this.colors = ["red", "blue"];
}
Parent.prototype.sayName = function () {
  console.log(this.name);
};
function Child(name) {
  Parent.call(this, name); // 借用构造函数继承属性
}
Child.prototype = new Parent(); // 原型链继承方法
const child1 = new Child("Child1");
child1.colors.push("green");
console.log(child1.colors); // 输出: ['red', 'blue', 'green']
child1.sayName(); // 输出: Child1
const child2 = new Child("Child2");
console.log(child2.colors); // 输出: ['red', 'blue']
child2.sayName(); // 输出: Child2优点:
- 解决了引用属性共享和方法复用的问题。 
- 可以向父类构造函数传参。 
缺点:
- 调用了两次父类构造函数(一次在 - Parent.call,一次在- new Parent()),性能略有损耗。
记忆技巧:
- 组合:想象把“借用构造函数”和“原型链”两种方式组合在一起。 
- 两次调用:记住父类构造函数被调用了两次。 
4. 寄生式继承
核心思想:
- 基于一个对象创建新对象,并增强新对象的能力。 
- 类似于工厂模式,常用于对象增强。 
代码示例:
function createAnother(original) {
  const clone = Object.create(original); // 基于原对象创建新对象
  clone.sayHi = function () {
    // 增强新对象
    console.log("Hi");
  };
  return clone;
}
const parent = { name: "Parent" };
const child = createAnother(parent);
child.sayHi(); // 输出: Hi
console.log(child.name); // 输出: Parent优点:
- 简单灵活,适合对象增强。 
缺点:
- 方法无法复用,每次创建对象都会重新定义方法。 
记忆技巧:
- 寄生:想象新对象“寄生”在原对象上,并增强了功能。 
- 工厂模式:记住它类似于工厂模式,用于创建增强对象。 
5. class 实现继承
核心思想:
- 使用 ES6 的 - class和- extends关键字实现继承。
- 语法更简洁,底层仍然是基于原型链。 
代码示例:
class Parent {
  constructor(name) {
    this.name = name;
  }
  sayName() {
    console.log(this.name);
  }
}
class Child extends Parent {
  constructor(name) {
    super(name); // 调用父类构造函数
  }
}
const child = new Child("Child");
child.sayName(); // 输出: Child优点:
- 语法简洁,易于理解。 
- 底层自动处理原型链和构造函数调用。 
缺点:
- 需要支持 ES6 的环境。 
记忆技巧:
- class 和 extends:记住这是 ES6 的语法糖,底层仍然是原型链。 
- super:记住 - super用于调用父类构造函数。
6. 寄生组合式继承
核心思想:
- 结合组合继承和寄生式继承。 
- 通过 Object.create() 创建父类原型的副本,避免调用两次父类构造函数。 
代码示例:
function Parent(name) {
  this.name = name;
  this.colors = ["red", "blue"];
}
Parent.prototype.sayName = function () {
  console.log(this.name);
};
function Child(name) {
  Parent.call(this, name); // 借用构造函数继承属性
}
// 寄生组合式继承
Child.prototype = Object.create(Parent.prototype); // 创建父类原型的副本
Child.prototype.constructor = Child; // 修复构造函数指向
const child1 = new Child("Child1");
child1.colors.push("green");
console.log(child1.colors); // 输出: ['red', 'blue', 'green']
child1.sayName(); // 输出: Child1
const child2 = new Child("Child2");
console.log(child2.colors); // 输出: ['red', 'blue']
child2.sayName(); // 输出: Child2优点: 解决了组合继承中调用两次父类构造函数的问题。
是 JavaScript 中最理想的继承方式。
记忆技巧: 寄生组合:想象“寄生”在父类原型上,同时“组合”了借用构造函数的方式。
总结与记忆技巧
- 原型链继承:链式连接,共享问题。 
- 借用构造函数继承:借用父类构造函数,无法复用方法。 
- 组合继承:组合两种方式,调用两次构造函数。 
- 寄生式继承:对象增强,工厂模式。 
- class 继承:ES6 语法糖,简洁易用。 
- 寄生组合式继承:组合继承的优化版本,最优继承方式。 
最后更新于
这有帮助吗?