JavaScript 核心机制:构造函数、原型链与 Class 语法解析
构造函数与原型对象的关系
在 JavaScript 中,每当声明一个函数时,引擎会在内存中自动为其创建一个关联的对象,这个对象被称为原型对象。函数(此时作为构造函数)内部会包含一个 prototype 属性,该属性直接指向这个原型对象。反之,原型对象内部也存在一个 constructor 属性,它指回构造函数本身。
function Vehicle(brand, year) {
this.brand = brand;
this.year = year;
}
// 验证 constructor 的指向
console.log(Vehicle.prototype.constructor === Vehicle); // true
// 实例化对象
const myCar = new Vehicle("Toyota", 2023);

实例化与原型链查找机制
使用 new 关键字调用构造函数会生成一个实例对象。需要注意的是,实例对象本身并没有 prototype 属性,但它拥有一个隐藏属性 __proto__。这个 __proto__ 属性直接指向构造函数的原型对象。
function Device(type) {
this.type = type;
}
const laptop = new Device("PC");
// 实例的 __proto__ 指向构造函数的 prototype
console.log(laptop.__proto__ === Device.prototype); // true

当我们在原型对象上添加属性或方法时,所有由该构造函数创建的实例都可以共享这些成员。实例在访问某个属性时,如果在自身找不到,就会顺着 __proto__ 向上查找原型对象,这就是原型链的核心机制。
Device.prototype.status = "active";
console.log(laptop.status); // "active" (从原型对象获取)
// 属性遮蔽 (Shadowing)
laptop.status = "offline";
console.log(laptop.status); // "offline" (访问实例自身的属性)
console.log(Device.prototype.status); // "active" (原型属性未被修改)

通过实例直接赋值(如 laptop.status = "offline"),并不会修改原型上的值,而是在实例自身创建了一个同名属性。这个新属性会"遮蔽"原型链上的同名属性,导致后续访问时只返回实例上的值。
Class 语法糖的本质
ES6 引入的 class 关键字本质上是基于原型链的语法糖,它让面向对象编程的写法更加清晰和接近传统语言。类中的方法会被自动挂载到构造函数的 prototype 上。
class Product {
constructor(name, price) {
this.name = name;
this.price = price;
}
// 实例方法,等同于 Product.prototype.getDetails = function() {...}
getDetails() {
return `${this.name} costs $${this.price}`;
}
}
const item = new Product("Laptop", 999);
console.log(item.getDetails());
实例成员与静态成员
在面向对象设计中,成员分为实例级别和类级别(静态):
- 实例属性/方法:必须通过
new创建实例后才能访问,通常定义在构造函数内部或原型上。 - 静态属性/方法:直接挂载在构造函数(或类)本身上,实例无法访问,只能通过类名调用。在
class中使用static关键字声明。
class Database {
// 静态属性
static defaultPort = 3306;
constructor(host) {
// 实例属性
this.host = host;
}
// 实例方法
query(sql) {
console.log(`Executing: ${sql} on ${this.host}`);
}
// 静态方法
static establishConnection() {
console.log(`Connecting via default port ${this.defaultPort}...`);
}
}
const db = new Database("localhost");
// 访问实例成员
console.log(db.host); // "localhost"
db.query("SELECT * FROM users");
// 访问静态成员
console.log(Database.defaultPort); // 3306
Database.establishConnection();
// 实例无法访问静态成员
console.log(db.defaultPort); // undefined

Class 的继承机制
使用 extends 关键字可以实现类的继承。在子类的 constructor 中,必须调用 super() 来执行父类的构造逻辑,从而正确初始化继承来的实例属性。
class Shape {
constructor(color) {
this.color = color;
}
}
class Rectangle extends Shape {
constructor(color, width, height) {
super(color); // 调用父类构造函数初始化 color
this.width = width;
this.height = height;
}
calculateArea() {
return this.width * this.height;
}
}
const myRect = new Rectangle("blue", 10, 20);
console.log(myRect.color); // "blue" (继承自父类)
console.log(myRect.calculateArea()); // 200
