JavaScript 中的类、类的原型和实例的异同
在 JavaScript 中,类(Class)、类的原型(Prototype)和实例(Instance)是面向对象编程的核心概念。下面我将详细解释它们的异同,并提供代码示例。
1. 基本概念
类 (Class)
- ES6 引入的语法糖,基于原型继承的封装
- 用于创建对象的模板
- 包含构造函数和方法的定义
类的原型 (Prototype)
- 每个 JavaScript 函数(包括类)都有一个 prototype 属性
- 包含该类的共享方法和属性
- 实例通过原型链继承这些属性和方法
实例 (Instance)
- 通过
new关键字调用类创建的具体对象 - 每个实例都有自己的属性,但共享原型上的方法
2. 三者的关系
类 (Class) → 类的原型 (Prototype) ← 实例 (Instance)
- 类定义了如何创建实例
- 类的原型是所有实例共享的方法和属性的存储位置
- 实例通过原型链访问原型上的方法和属性
3. 代码示例
// 定义一个类
class Person {
// 构造函数,用于初始化实例属性
constructor(name, age) {
this.name = name; // 实例属性
this.age = age; // 实例属性
}
// 实例方法(实际上会被添加到Person.prototype上)
greet() {
console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
}
// 静态方法(属于类本身,不属于实例)
static species() {
return 'Homo sapiens';
}
}
// 1. 类本身
console.log(typeof Person); // "function"(类实际上是函数)
console.log(Person.species()); // "Homo sapiens"(调用静态方法)
// 2. 类的原型
console.log(Person.prototype); // 包含greet方法
console.log(Person.prototype.constructor === Person); // true
// 3. 创建实例
const person1 = new Person('Alice', 30);
const person2 = new Person('Bob', 25);
// 实例访问属性和方法
console.log(person1.name); // "Alice"(实例属性)
person1.greet(); // 调用原型上的方法
// 检查原型链关系
console.log(person1.__proto__ === Person.prototype); // true
console.log(person1 instanceof Person); // true
// 添加方法到原型(会影响所有实例)
Person.prototype.sayGoodbye = function() {
console.log(`Goodbye from ${this.name}!`);
};
person1.sayGoodbye(); // "Goodbye from Alice!"
person2.sayGoodbye(); // "Goodbye from Bob!"
4. 三者的主要区别
| 特性 | 类 (Class) | 类的原型 (Prototype) | 实例 (Instance) |
|---|---|---|---|
| 定义位置 | 使用 class 关键字定义 | 自动创建,通过 ClassName.prototype 访问 | 通过 new ClassName() 创建 |
| 包含内容 | 构造函数、静态方法 | 共享的方法和属性 | 实例特有的属性 |
| 访问方式 | 直接通过类名访问 | 通过 ClassName.prototype 或 instance.__proto__ | 通过变量名访问 |
| 是否可被继承 | 是(通过 extends) | 是(通过原型链) | 否 |
| 内存中的存在 | 只有一个类定义 | 只有一个原型对象 | 可以有多个实例 |
5. 更深入的原型链示例
class Animal {
constructor(name) {
this.name = name;
}
eat() {
console.log(`${this.name} is eating.`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name);
this.breed = breed;
}
bark() {
console.log(`${this.name} is barking!`);
}
}
const myDog = new Dog('Rex', 'Labrador');
// 原型链关系
console.log(myDog.__proto__ === Dog.prototype); // true
console.log(Dog.prototype.__proto__ === Animal.prototype); // true
console.log(Animal.prototype.__proto__ === Object.prototype); // true
// 方法查找过程
myDog.eat(); // 先在Dog.prototype找,没有就去Animal.prototype找
myDog.bark(); // 在Dog.prototype找到
myDog.toString(); // 最终在Object.prototype找到
6. 总结
- 类是创建对象的模板,提供了更清晰的语法来创建构造函数和原型
- 原型是所有实例共享的方法和属性的存储位置,实现了方法的共享和继承
- 实例是根据类创建的具体对象,拥有自己的属性,但共享原型上的方法
理解这三者的关系对于掌握 JavaScript 的面向对象编程至关重要。原型继承是 JavaScript 的核心特性,即使使用 class 语法,底层仍然是基于原型的实现。