您的位置:

JavaScript继承详解

一、ES6中的继承

ES6中提供了完整的类系统,并且支持extends关键字来实现继承。在ES6之前,JavaScript并没有原生的面向对象的类系统,类的概念只是通过函数和原型继承来模拟的。下面是一个ES6中继承的示例代码:

class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(this.name + ' makes a noise.');
  }
}

class Dog extends Animal {
  constructor(name) {
    super(name); 
  }

  speak() {
    console.log(this.name + ' barks.');
  }
}

let d = new Dog('Mitzie');
d.speak(); //输出:Mitzie barks.

在以上示例中,我们定义了一个Animal类和一个Dog类,Dog类从Animal类中继承了构造函数、属性和方法,并重写了speak方法。在创建Dog实例时,我们通过new关键字创建了一个Dog实例,然后调用其speak方法。

二、原型链继承

原型链是JavaScript中实现继承的主要方式之一。通过原型链,我们可以将一个对象的属性和方法继承到另一个对象中。我们将创建一个父类Person和一个子类Student并继承Person的示例代码。

function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.eat = function() {
  console.log(this.name + ' eat something.');
}

function Student(name, age, grade) {
  this.grade = grade;
  Person.call(this, name, age);
}

Student.prototype = new Person();
Student.prototype.constructor = Student;

Student.prototype.study = function() {
  console.log(this.name + ' study in ' + this.grade + ' grade.');
}

let s = new Student('John', 18, 5);
s.eat(); //输出:John eat something.
s.study(); //输出:John study in 5 grade.

在以上示例中,Person是一个父类,Student继承了Person并添加了一个study方法。通过调用Person.call方法,我们将Person的属性绑定到Student对象上然后用Student的prototype指向Person的实例,以便子类可以共享父类的属性和方法。

三、构造函数继承

通过构造函数继承,我们可以在子类中调用父类的构造函数,并将父类的属性和方法添加到子类的实例中。下面是构造函数继承的示例代码。

function Animal(name) {
  this.name = name;
}

Animal.prototype.speak = function() {
  console.log('This is ' + this.name + '.');
}

function Dog(name, breed) {
  Animal.call(this, name);
  this.breed = breed;
}

let d = new Dog('Mitzie', 'Dalmatian');
console.log(d.name); //输出:Mitzie
console.log(d.breed); //输出:Dalmatian
d.speak(); //报错,因为speak方法不是Dog类的原型方法

在以上示例中,我们定义了一个Animal类和一个Dog类,并用Animal.call方法来实现继承。通过调用父类的构造函数,我们将父类的属性绑定到子类对象上,以便子类可以共享父类的属性和方法。

四、组合继承

组合继承是将上面两种方式结合起来使用。在组合继承中,我们通过构造函数继承来继承父类的属性,然后通过原型链继承来继承父类的方法。下面是组合继承的示例代码。

function Animal(name) {
  this.name = name;
}

Animal.prototype.speak = function() {
  console.log('This is ' + this.name + '.');
}

function Dog(name, breed) {
  Animal.call(this, name);
  this.breed = breed;
}

Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;

let d = new Dog('Mitzie', 'Dalmatian');
console.log(d.name); //输出:Mitzie
console.log(d.breed); //输出:Dalmatian
d.speak(); //输出:This is Mitzie.

在以上示例中,我们通过Animal.call来实现构造函数继承,然后通过Dog.prototype = new Animal()来实现原型链继承。通过这两种方式,我们可以继承父类的属性和方法。

五、ES6中的Super

在ES6的类系统中,我们可以使用super关键字来调用父类的构造函数和方法。在以下示例中,我们将用super关键字创建一个Animal类,并在Dog类中继承Animal,并调用父类的构造函数和方法。

class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log('This is ' + this.name + '.');
  }
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name);
    this.breed = breed;
  }

  bark() {
    console.log(this.name + ' barks.');
  }
}

let d = new Dog('Mitzie', 'Dalmatian');
console.log(d.name); //输出:Mitzie
console.log(d.breed); //输出:Dalmatian
d.speak(); //输出:This is Mitzie.
d.bark(); //输出:Mitzie barks.

在以上示例中,我们通过super关键字调用了Animal的构造函数,然后通过super.speak()调用了Animal的speak方法。这个语法糖方便了我们在ES6中实现继承。

六、总结

JavaScript中有多种实现继承的方式,每种方式都有其优缺点,我们需要根据具体的应用场景来选择实现方式。ES6中提供了完整的类系统和super关键字,方便了我们进行继承。