
本文详解 JavaScript 类中 getter/setter 的常见递归错误,通过使用私有字段(_temperature 或 #temperature)避免无限递归,确保温度单位转换逻辑正确、安全且符合封装原则。
本文详解 javascript 类中 getter/setter 的常见递归错误,通过使用私有字段(`_temperature` 或 `#temperature`)避免无限递归,确保温度单位转换逻辑正确、安全且符合封装原则。
在 JavaScript 中,为类定义 getter 和 setter 时,一个经典陷阱是:在 getter/setter 内部直接访问同名属性(如 this.temperature),导致隐式调用自身,引发无限递归与栈溢出。原始代码正是如此:
class Thermostat {
constructor(temperature) {
this.temperature = temperature; // ❌ 触发 setter → 再次调用 this.temperature = ...
}
get temperature() {
return 5/9 * (this.temperature - 32); // ❌ 触发 getter → 无限循环
}
set temperature(updatedTemperature) {
this.temperature = 9 * updatedTemperature / 5 + 32; // ❌ 再次触发 setter
}
}
问题根源在于:this.temperature 在 getter/setter 内部不指向普通数据属性,而是持续触发对应的访问器方法,形成死循环。
✅ 正确解法是引入独立的底层存储字段,与访问器名称严格分离。推荐两种现代、规范的方式:
方案一:约定私有字段(下划线前缀 _temperature)
语义清晰、兼容性好(所有 ES6+ 环境支持),适用于需兼顾旧环境的项目:
class Thermostat {
constructor(fahrenheit) {
this._temperature = fahrenheit; // ✅ 存储原始 Fahrenheit 值
}
get temperature() {
return parseFloat((5/9 * (this._temperature - 32)).toFixed(2)); // 返回摄氏值,保留两位小数
}
set temperature(celsius) {
this._temperature = celsius * 9 / 5 + 32; // ✅ 转换为华氏后存入私有字段
}
}
const thermos = new Thermostat(76);
console.log(thermos.temperature); // 24.44(Celsius)
thermos.temperature = 26;
console.log(thermos.temperature); // 26(Celsius)
方案二:真私有字段(#temperature,ES2022+)
提供语言级封装,不可被外部访问或篡改,更安全可靠:
class Thermostat {
#temperature = 0;
constructor(fahrenheit) {
this.#temperature = fahrenheit;
}
get temperature() {
return parseFloat((5/9 * (this.#temperature - 32)).toFixed(2));
}
set temperature(celsius) {
this.#temperature = celsius * 9 / 5 + 32;
}
}
⚠️ 注意事项:
- 永远不要在 getter/setter 中读写同名属性(this.xxx),必须通过不同名称的字段承载状态;
- 温度计算涉及浮点运算,建议使用 parseFloat(...toFixed(2)) 提升可读性;
- 使用 # 私有字段时,确保运行环境支持(Node.js ≥16.0,Chrome ≥91,Firefox ≥90 等);
- 封装的本质是“对外提供统一接口,对内隐藏实现细节”——用户只关心 thermos.temperature 是摄氏值,无需知道内部存的是华氏。
通过这种设计,Thermostat 成功实现了 API 抽象:使用者始终以摄氏度交互,而类内部自由选择最优存储格式(此处为华氏),既保障了灵活性,又杜绝了逻辑错误。










