穿越 JavaScript 继承方法的迷宫:从理论到实践的清晰指南
2023-12-03 08:48:59
前言
在 JavaScript 的世界中,继承是构建复杂应用程序的关键。它允许您从现有类创建新类,从而复用代码并实现代码的可扩展性。ES6 以前,JavaScript 中的继承不像其它面向对象语言一样,用特定 class 去实现,它是由构造函数和原型去模拟。本文将深入剖析 JavaScript 中的各种继承方法,从经典继承到 ES6 的类继承,为您提供全方位的理解和实践指南。
原型链
原型链是 JavaScript 中实现继承的基础。每个对象都有一个原型对象,原型对象也是一个对象,它包含了该对象继承的属性和方法。当访问一个对象的属性或方法时,JavaScript 会首先在该对象中查找,如果找不到,就会沿着原型链向上查找,直到找到该属性或方法。
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log(`Hello, my name is ${this.name}`);
};
function Student(name, major) {
Person.call(this, name);
this.major = major;
}
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
const student = new Student('John Doe', 'Computer Science');
student.greet(); // Hello, my name is John Doe
在这个例子中,Student
类继承了 Person
类。Student
类的原型对象是 Person
类的原型对象的副本,因此 Student
类继承了 Person
类的所有属性和方法。
经典继承
经典继承是 JavaScript 中最简单的继承方法。它通过使用 new
运算符调用父类的构造函数来实现。
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log(`Hello, my name is ${this.name}`);
};
function Student(name, major) {
Person.call(this, name);
this.major = major;
}
const student = new Student('John Doe', 'Computer Science');
student.greet(); // Hello, my name is John Doe
在这个例子中,Student
类继承了 Person
类。当创建一个 Student
对象时,Person
类的构造函数会被调用,并且 Student
对象的原型对象被设置为 Person
类的原型对象。
原型继承
原型继承是另一种实现继承的方法。它通过直接将子类的原型对象设置为父类的原型对象来实现。
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log(`Hello, my name is ${this.name}`);
};
function Student() {}
Student.prototype = Person.prototype;
const student = new Student();
student.name = 'John Doe';
student.greet(); // Hello, my name is John Doe
在这个例子中,Student
类继承了 Person
类。当创建一个 Student
对象时,Student
对象的原型对象被设置为 Person
类的原型对象。
组合继承
组合继承是经典继承和原型继承的组合。它通过使用 new
运算符调用父类的构造函数来实现,并且将子类的原型对象设置为父类的原型对象的副本。
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log(`Hello, my name is ${this.name}`);
};
function Student(name, major) {
Person.call(this, name);
this.major = major;
}
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
const student = new Student('John Doe', 'Computer Science');
student.greet(); // Hello, my name is John Doe
在这个例子中,Student
类继承了 Person
类。当创建一个 Student
对象时,Person
类的构造函数会被调用,并且 Student
对象的原型对象被设置为 Person
类的原型对象的副本。
寄生继承
寄生继承是通过创建一个新对象,并将父类的方法和属性复制到该对象来实现继承。
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log(`Hello, my name is ${this.name}`);
};
function Student(name, major) {
const student = new Person(name);
student.major = major;
return student;
}
const student = Student('John Doe', 'Computer Science');
student.greet(); // Hello, my name is John Doe
在这个例子中,Student
类继承了 Person
类。当创建一个 Student
对象时,首先创建一个 Person
对象,然后将 Person
对象的方法和属性复制到 Student
对象。
委托继承
委托继承是通过在子类中创建一个私有属性,并将其设置为父类对象的引用来实现继承。
class Person {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hello, my name is ${this.name}`);
}
}
class Student extends Person {
constructor(name, major) {
super(name);
this.major = major;
}
greet() {
super.greet();
console.log(`My major is ${this.major}`);
}
}
const student = new Student('John Doe', 'Computer Science');
student.greet(); // Hello, my name is John Doe, My major is Computer Science
在这个例子中,Student
类继承了 Person
类。当创建一个 Student
对象时,首先创建一个 Person
对象,然后将 Person
对象的方法和属性复制到 Student
对象。
ES6 类继承
ES6 引入了 class ,使得 JavaScript 中的继承更加简洁和清晰。
class Person {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hello, my name is ${this.name}`);
}
}
class Student extends Person {
constructor(name, major) {
super(name);
this.major = major;
}
greet() {
super.greet();
console.log(`My major is ${this.major}`);
}
}
const student = new Student('John Doe', 'Computer Science');
student.greet(); // Hello, my name is John Doe, My major is Computer Science
在这个例子中,Student
类继承了 Person
类。当创建一个 Student
对象时,首先创建一个 Person
对象,然后将 Person
对象的方法和属性复制到 Student
对象。
总结
JavaScript 中的继承机制是灵活而强大的。您可以根据自己的需要选择不同的继承方法。在选择继承方法时,需要考虑以下几点:
- 继承的深度:继承的深度是指子类与父类的距离。继承的深度越深,子类继承的属性和方法就越多。
- 继承的类型:继承的类型是指子类继承父类的哪一部分。继承的类型可以是单继承、多继承或混合继承。
- 继承的开销:继承的开销是指子类继承父类的属性和方法所产生的性能开销。继承的开销越大,子类的性能就越差。
希望本文对您理解 JavaScript 中的继承有所帮助。