一、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关键字,方便了我们进行继承。