第三十八天:Class — 面向对象的现代写法
蜗牛往上爬 · 前端工业可视化学习笔记 第 38 篇
第 10 周学过构造函数 + 原型继承,ES6 给了它们一套更优雅的语法——Class。今天学 class 定义、getter/setter、私有字段、静态成员和 extends 继承,把设备建模升级为专业的类体系。
目录
一、从构造函数到 Class
// ES5:构造函数 + 原型
function Device(id, name) {
this.id = id;
this.name = name;
}
Device.prototype.getStatus = function () {
return `${this.name} 运行中`;
};
// ES6:Class(本质相同,语法更清晰)
class Device {
constructor(id, name) {
this.id = id;
this.name = name;
}
getStatus() {
return `${this.name} 运行中`;
}
}
const device = new Device("CNC-001", "数控机床");
console.log(device.getStatus()); // "数控机床 运行中"
console.log(typeof Device); // "function" ⭐ 本质还是函数!
三个规则:
方法自动挂到
prototype,实例共享类必须先定义再使用(无提升)
必须 new 调用,直接调用报错
二、getter / setter
像属性一样访问,但内部可以有逻辑和校验:
class Device {
constructor(temp) {
this._temp = temp;
}
get temp() {
return this._temp; // 像属性一样读:device.temp
}
set temp(value) {
if (value < -50 || value > 200) {
throw new Error("温度超出合理范围");
}
this._temp = value; // 像属性一样写:device.temp = 85
}
get level() { // getter 计算派生值
if (this._temp >= 80) return "危险";
if (this._temp >= 60) return "偏高";
return "正常";
}
}
const device = new Device(65);
console.log(device.temp); // 65(不用加括号)
console.log(device.level); // "偏高"
device.temp = 85; // setter 校验
console.log(device.level); // "危险"
三、私有字段
# 开头的字段类外部无法访问——真正的私有(比 _约定 更硬):
class Counter {
#count = 0; // 私有字段
increment() {
this.#count++; // 内部可用
return this.#count;
}
get value() {
return this.#count;
}
}
const c = new Counter();
c.increment();
c.increment();
console.log(c.value); // 2
// console.log(c.#count); // ❌ 语法错误
四、静态成员 static
静态成员属于类本身,不需要实例:
class DeviceManager {
static total = 0; // 静态属性:全局计数
constructor(id) {
this.id = id;
DeviceManager.total++;
}
// 静态方法:工具性质
static isDangerous(temp) {
return temp >= 80;
}
}
new DeviceManager("CNC-001");
new DeviceManager("AGV-002");
console.log(DeviceManager.total); // 2
console.log(DeviceManager.isDangerous(85)); // true
五、继承 extends 与 super
class Device {
constructor(id, name, temp) {
this.id = id;
this.name = name;
this.temp = temp;
}
getStatus() {
return `${this.id} ${this.name} 温度 ${this.temp}°C`;
}
report() {
return `【设备】${this.getStatus()}`;
}
}
class CNC extends Device {
constructor(id, name, temp, spindleSpeed) {
super(id, name, temp); // ⭐ 必须在 this 之前调用
this.spindleSpeed = spindleSpeed;
}
startSpindle() { // 子类特有方法
return `${this.name} 主轴 ${this.spindleSpeed}rpm`;
}
report() { // ⭐ 重写父类方法
return `${super.report()}(主轴 ${this.spindleSpeed}rpm)`;
}
}
const cnc = new CNC("CNC-001", "数控机床", 65, 1200);
console.log(cnc.getStatus()); // 继承的方法
console.log(cnc.report()); // 重写后的方法
console.log(cnc instanceof Device); // true(子类实例也是父类实例)
继承三要点:
extends继承全部属性方法constructor 里先
super(...)再用this同名重写,
super.方法()调父类版本
六、实战:设备类继承体系
/** 设备基类 */
class Device {
constructor(id, name, temp = 0) {
this.id = id;
this.name = name;
this.temp = temp;
}
get level() {
if (this.temp >= 80) return "危险";
if (this.temp >= 60) return "偏高";
return "正常";
}
toJSON() {
return { id: this.id, name: this.name, temp: this.temp, level: this.level };
}
}
/** 数控机床 */
class CNC extends Device {
constructor(id, name, temp, spindleSpeed = 0) {
super(id, name, temp);
this.spindleSpeed = spindleSpeed;
}
toJSON() {
return { ...super.toJSON(), spindleSpeed: this.spindleSpeed };
}
}
/** AGV 搬运车 */
class AGV extends Device {
constructor(id, name, temp, battery = 100) {
super(id, name, temp);
this.battery = battery;
}
get isLowBattery() {
return this.battery < 20;
}
toJSON() {
return { ...super.toJSON(), battery: this.battery };
}
}
// ===== 多态:同一方法,不同行为 =====
const devices = [
new CNC("CNC-001", "数控机床", 65, 1200),
new AGV("AGV-002", "搬运车", 42, 15),
new Device("ARM-003", "机械臂", 38)
];
devices.forEach(d => console.log(d.toJSON())); // 各自的实现
// 低电量 AGV 筛选
const lowBattery = devices.filter(d => d instanceof AGV && d.isLowBattery);
console.log(lowBattery.map(d => d.id)); // ["AGV-002"]
七、总结
🎯 Class 让设备建模更专业。明天学 ES Module——把类和工具拆成独立文件,走向工程化!