一文带你看到JS的继承

64 阅读2分钟
  1. 原型链继承(Prototype Inheritance)
// 父类
function Animal(name) {
    this.name = name;
}
// 父类方法
Animal.prototype.sayName = function() {
    console.log('My name is ' + this.name);
};

// 子类
function Dog(name, breed) {
    Animal.call(this, name);
    this.breed = breed;
}
// 子类继承父类
Dog.prototype = new Animal();

// 创建实例
var myDog = new Dog('Buddy', 'Labrador');
myDog.sayName(); // 输出:My name is Buddy

优点

  • 简单易懂,原型链清晰。
  • 父类的属性和方法可以被子类共享。

缺点

  • 所有子类实例共享同一个父类实例,可能导致子类实例之间的属性共享问题。
  • 无法在不影响所有子类实例的情况下向父类构造函数传递参数。
  1. 构造函数继承(Constructor Inheritance)
// 父类
function Animal(name) {
    this.name = name;
}
// 父类方法
Animal.prototype.sayName = function() {
    console.log('My name is ' + this.name);
};

// 子类
function Dog(name, breed) {
    Animal.call(this, name); // 调用父类构造函数
    this.breed = breed;
}

// 创建实例
var myDog = new Dog('Buddy', 'Labrador');
myDog.sayName(); // 错误:myDog.sayName is not a function

优点

  • 可以向父类构造函数传递参数,使得子类实例可以拥有独立的属性。

缺点

  • 无法继承父类原型上的方法。
  • 每个子类实例都有自己的一份父类属性的副本,可能造成内存浪费。
  1. 组合继承(Combination Inheritance)
// 父类
function Animal(name) {
    this.name = name;
}
// 父类方法
Animal.prototype.sayName = function() {
    console.log('My name is ' + this.name);
};

// 子类
function Dog(name, breed) {
    Animal.call(this, name); // 调用父类构造函数
    this.breed = breed;
}
// 子类继承父类
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;

// 创建实例
var myDog = new Dog('Buddy', 'Labrador');
myDog.sayName(); // 输出:My name is Buddy

优点

  • 既继承了父类的属性,又继承了父类原型上的方法。
  • 可以向父类构造函数传递参数,使得子类实例可以拥有独立的属性。

缺点

  • 调用两次父类构造函数,可能会影响性能。
  1. 原型式继承(Prototype-based Inheritance)
// 原型对象
var animal = {
    sayName: function() {
        console.log('My name is ' + this.name);
    }
};

// 创建新对象并继承原型
var dog = Object.create(animal);
dog.name = 'Buddy';

// 调用方法
dog.sayName(); // 输出:My name is Buddy

优点

  • 简单快捷,无需定义构造函数。
  • 可以轻松地创建多个对象,并且可以选择性地修改继承的属性。

缺点

  • 无法实现私有成员和方法。
  • 所有对象共享同一个原型对象,可能导致意外的修改和副作用。
  1. ES6中的类继承
// 父类
class Animal {
    constructor(name) {
        this.name = name;
    }
    sayName() {
        console.log('My name is ' + this.name);
    }
}

// 子类
class Dog extends Animal {
    constructor(name, breed) {
        super(name); // 调用父类构造函数
        this.breed = breed;
    }
}

// 创建实例
let myDog = new Dog('Buddy', 'Labrador');
myDog.sayName(); // 输出:My name is Buddy

优点

  • 语法简洁清晰,易于理解和维护。
  • 可以继承父类的属性和方法,并且可以调用父类构造函数。

缺点

  • 不支持私有属性和方法。
  • 对于一些旧版本的JavaScript引擎可能不完全支持。

这些继承方式各有优缺点,具体使用时需要根据实际情况选择合适的方式。常见的优点包括代码复用、灵活性和可维护性,而缺点主要涉及性能、内存占用和代码复杂度等方面。