JavaScript 的继承方式及代码示例
JavaScript 是一种基于原型的语言,它提供了多种实现继承的方式。以下是主要的几种继承方式及其代码示例:
1. 原型链继承
javascript
function Parent() {
this.name = 'Parent';
this.colors = ['red', 'blue', 'green'];
}
Parent.prototype.getName = function() {
return this.name;
};
function Child() {
this.childName = 'Child';
}
// 继承 Parent
Child.prototype = new Parent();
const child1 = new Child();
console.log(child1.getName()); // "Parent"
console.log(child1.childName); // "Child"
// 问题:引用类型的属性会被所有实例共享
const child2 = new Child();
child1.colors.push('black');
console.log(child2.colors); // ["red", "blue", "green", "black"]
2. 构造函数继承(经典继承)
javascript
function Parent(name) {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
Parent.prototype.getName = function() {
return this.name;
};
function Child(name, age) {
Parent.call(this, name); // 调用父类构造函数
this.age = age;
}
const child1 = new Child('Tom', 18);
console.log(child1.name); // "Tom"
console.log(child1.age); // 18
// 引用类型属性不会被共享
const child2 = new Child('Jerry', 20);
child1.colors.push('black');
console.log(child2.colors); // ["red", "blue", "green"]
// 问题:无法继承父类原型上的方法
console.log(child1.getName); // undefined
3. 组合继承(原型链 + 构造函数)
javascript
function Parent(name) {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
Parent.prototype.getName = function() {
return this.name;
};
function Child(name, age) {
Parent.call(this, name); // 第二次调用 Parent
this.age = age;
}
// 第一次调用 Parent
Child.prototype = new Parent();
Child.prototype.constructor = Child;
const child1 = new Child('Tom', 18);
console.log(child1.getName()); // "Tom"
console.log(child1.age); // 18
const child2 = new Child('Jerry', 20);
child1.colors.push('black');
console.log(child2.colors); // ["red", "blue", "green"]
4. 原型式继承
javascript
function createObj(o) {
function F() {}
F.prototype = o;
return new F();
}
const person = {
name: 'Person',
colors: ['red', 'blue', 'green']
};
const person1 = createObj(person);
person1.name = 'Tom';
person1.colors.push('black');
const person2 = createObj(person);
console.log(person2.name); // "Person"
console.log(person2.colors); // ["red", "blue", "green", "black"]
5. 寄生式继承
javascript
function createAnother(original) {
const clone = Object.create(original); // 通过调用函数创建一个新对象
clone.sayHi = function() { // 以某种方式增强这个对象
console.log('Hi');
};
return clone;
}
const person = {
name: 'Person',
colors: ['red', 'blue', 'green']
};
const anotherPerson = createAnother(person);
anotherPerson.sayHi(); // "Hi"
6. 寄生组合式继承(最理想的方式)
javascript
function inheritPrototype(child, parent) {
const prototype = Object.create(parent.prototype); // 创建对象
prototype.constructor = child; // 增强对象
child.prototype = prototype; // 指定对象
}
function Parent(name) {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
Parent.prototype.getName = function() {
return this.name;
};
function Child(name, age) {
Parent.call(this, name);
this.age = age;
}
// 将父类原型赋值给子类
inheritPrototype(Child, Parent);
// 添加子类方法
Child.prototype.getAge = function() {
return this.age;
};
const child1 = new Child('Tom', 18);
console.log(child1.getName()); // "Tom"
console.log(child1.getAge()); // 18
7. ES6 Class 继承
javascript
class Parent {
constructor(name) {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
getName() {
return this.name;
}
}
class Child extends Parent {
constructor(name, age) {
super(name); // 调用父类的constructor
this.age = age;
}
getAge() {
return this.age;
}
}
const child1 = new Child('Tom', 18);
console.log(child1.getName()); // "Tom"
console.log(child1.getAge()); // 18
const child2 = new Child('Jerry', 20);
child1.colors.push('black');
console.log(child2.colors); // ["red", "blue", "green"]
总结
- 原型链继承:简单但引用属性共享
- 构造函数继承:解决属性共享问题但无法继承原型方法
- 组合继承:结合前两者优点但调用两次父类构造函数
- 原型式继承:类似Object.create()的浅复制
- 寄生式继承:增强对象但方法不能复用
- 寄生组合式继承:最理想的继承方式
- ES6 Class:语法糖,底层基于寄生组合式继承
现代开发中推荐使用ES6的class语法,它简洁且易于理解,底层实现也是最优的继承方式。
相关文章: Typescript中的继承示例