举例说明js如何实现继承?
JS实现继承主要有以下几种方式,我将分别举例说明:
1. 原型链继承:
这是最基本的继承方式,核心是将子类型的原型指向父类型的实例。
function Parent(name) {
this.name = name;
}
Parent.prototype.sayName = function() {
console.log("My name is " + this.name);
};
function Child(name, age) {
this.age = age;
}
Child.prototype = new Parent("Parent Name"); // Child的原型指向Parent的实例
Child.prototype.constructor = Child; // 修正constructor指向
let child1 = new Child("Child Name", 10);
child1.sayName(); // 输出: My name is Parent Name (继承自Parent)
console.log(child1.age); // 输出: 10
console.log(child1 instanceof Parent); // 输出: true
console.log(child1 instanceof Child); // 输出: true
优点: 简单易懂。
缺点:
- 所有子类实例共享父类实例的属性,修改一个实例的属性会影响其他实例。
- 创建子类实例时无法向父类构造函数传参。
2. 构造函数继承 (借用构造函数):
通过在子类型构造函数中调用父类型构造函数来继承父类型的属性。
function Parent(name) {
this.name = name;
}
function Child(name, age) {
Parent.call(this, name); // 调用Parent构造函数
this.age = age;
}
let child1 = new Child("Child Name", 10);
child1.sayName(); // 报错: child1.sayName is not a function (没有继承父类方法)
console.log(child1.name); // 输出: Child Name
console.log(child1.age); // 输出: 10
console.log(child1 instanceof Parent); // 输出: false
console.log(child1 instanceof Child); // 输出: true
优点:
- 解决了原型链继承共享属性的问题。
- 可以在创建子类实例时向父类构造函数传参。
缺点:
- 无法继承父类原型上的方法和属性,只能继承父类构造函数中的属性。
- 每次创建子类实例都会重复执行父类构造函数中的代码,造成性能浪费。
3. 组合继承 (原型链继承 + 构造函数继承):
结合了原型链继承和构造函数继承的优点。
function Parent(name) {
this.name = name;
}
Parent.prototype.sayName = function() {
console.log("My name is " + this.name);
};
function Child(name, age) {
Parent.call(this, name); // 继承属性
this.age = age;
}
Child.prototype = Object.create(Parent.prototype); // 继承方法
Child.prototype.constructor = Child; // 修正constructor指向
let child1 = new Child("Child Name", 10);
child1.sayName(); // 输出: My name is Child Name
console.log(child1.age); // 输出: 10
console.log(child1 instanceof Parent); // 输出: true
console.log(child1 instanceof Child); // 输出: true
优点: 结合了两种继承方式的优点,既可以继承父类构造函数中的属性,也可以继承父类原型上的方法。
缺点: 父类构造函数会被调用两次(一次在创建子类原型时,一次在子类构造函数中),造成一定的性能浪费。
4. ES6 Class 继承 (extends):
ES6 提供了更简洁的 class
语法和 extends
关键字来实现继承。
class Parent {
constructor(name) {
this.name = name;
}
sayName() {
console.log("My name is " + this.name);
}
}
class Child extends Parent {
constructor(name, age) {
super(name); // 调用父类构造函数
this.age = age;
}
}
let child1 = new Child("Child Name", 10);
child1.sayName(); // 输出: My name is Child Name
console.log(child1.age); // 输出: 10
console.log(child1 instanceof Parent); // 输出: true
console.log(child1 instanceof Child);