编程新手咨询:属性值应在设置还是获取时调整?及#1与#2的差异与最佳实践
嘿,作为刚入门的编程新手,你的这两个问题其实是很多人刚开始接触属性访问器时都会踩的坑,我来给你掰扯清楚~
问题1:调整属性值该在set还是get阶段操作?
结论先行:一定要在set阶段处理属性值的调整,绝对不要在get里做修改操作!
先搞清楚set和get的本质职责:
set方法的核心就是接收外部传入的值,对其进行校验、转换、存储,它是专门用来处理“赋值”这个动作的,逻辑清晰可控。- 而
get方法的唯一职责是返回当前存储的属性值,它必须是“无副作用”的——意思就是调用get的时候,除了返回值,不能修改任何变量或状态,否则会导致各种诡异的bug。
举个实际的例子:比如你想把用户输入的用户名统一转成小写。
- 正确做法(在set里处理):
class User { #username; set username(value) { // 赋值时统一转小写,存储的就是处理后的值 this.#username = value.toLowerCase(); } get username() { // 只返回存储好的值,啥也不修改 return this.#username; } } const user = new User(); user.username = "JOHNDoe"; console.log(user.username); // 输出"johndoe",不管赋值多少次,只会处理一次
- 错误做法(在get里处理):
class User { #username; set username(value) { this.#username = value; } get username() { // 每次获取都转小写,会导致不可预测的问题 this.#username = this.#username.toLowerCase(); return this.#username; } } const user = new User(); user.username = "JOHNDoe"; console.log(user.username); // 第一次输出"johndoe" // 如果后续有逻辑需要用到原始的"JOHNDoe",已经完全找不回来了
简单说:set管“存”的时候处理,get只管“取”的时候返回,职责分离才不会出乱子。
问题2:#1与#2的最佳实践及差异
由于你没贴#1和#2的具体代码,我就基于最常见的两种属性处理场景来解释(这也是新手问这个问题时最常遇到的情况):
- #1:在setter中完成属性值的校验、转换
- #2:在getter中完成属性值的转换或计算
核心差异
- 执行时机:#1只有当属性被赋值时才执行一次;#2每次获取属性值时都会执行。
- 状态稳定性:#1只修改存储的值一次,状态始终稳定;#2如果修改存储值会导致状态不可控,即便只是计算临时值,频繁调用也可能影响性能。
- 职责匹配度:#1完全符合setter“处理赋值”的职责;#2仅在“基于原始值计算临时结果”时符合getter的职责,若修改存储值则完全违背设计初衷。
各自的最佳实践
对于#1(setter处理):
- 这是属性处理的首选方案,适合所有需要标准化存储值的场景:比如类型转换(字符串转数字、大小写统一)、范围校验(年龄不能小于0)、格式修正(手机号加区号)。
- 最佳实践:处理后的值一定要存储到私有变量(比如JS里的
#privateVar),不要直接操作公共属性,避免触发无限递归。
对于#2(getter处理):
- 仅适合一种场景:不需要修改原始存储值,只是基于原始值计算临时结果。比如根据存储的出生日期计算当前年龄,或者把存储的RGB值转成十六进制字符串。
- 绝对禁止在getter里修改存储的属性值!这是新手最容易踩的坑,会导致状态混乱、调试困难。
举个#2的正确用法例子:
class User { #birthYear; constructor(birthYear) { this.#birthYear = birthYear; } get age() { // 基于存储的出生年份计算当前年龄,不修改原始值 return new Date().getFullYear() - this.#birthYear; } } const user = new User(2000); console.log(user.age); // 24(假设当前是2024) // 下次再获取时会重新计算,自动更新年龄,这是合理的
内容的提问来源于stack exchange,提问作者Niki
相关产品推荐
相关产品推荐

