JavaScript教程:深入理解对象属性的getter和setter

JavaScript教程:深入理解对象属性的getter和setter

zh.javascript.info 现代 JavaScript 教程(The Modern JavaScript Tutorial),以最新的 ECMAScript 规范为基准,通过简单但足够详细的内容,为你讲解从基础到高阶的 JavaScript 相关知识。 zh.javascript.info 项目地址: https://gitcode.com/gh_mirrors/zh/zh.javascript.info

在JavaScript中,对象属性可以分为两种主要类型:数据属性和访问器属性。本文将重点介绍访问器属性,也就是我们常说的getter和setter方法。

数据属性与访问器属性的区别

数据属性是我们最常用的属性类型,它们直接存储值。而访问器属性则不同:

  • 数据属性:直接存储值,可以通过赋值操作修改
  • 访问器属性:不直接存储值,而是通过getter和setter方法来控制属性的读取和写入

基本语法和使用

访问器属性在对象字面量中使用getset关键字定义:

let obj = {
  get propName() {
    // 读取属性时执行的代码
  },
  
  set propName(value) {
    // 设置属性时执行的代码
  }
};

实际应用示例

考虑一个用户对象,包含姓名和姓氏:

let user = {
  name: "张",
  surname: "三",
  
  get fullName() {
    return `${this.name} ${this.surname}`;
  },
  
  set fullName(value) {
    [this.name, this.surname] = value.split(" ");
  }
};

console.log(user.fullName); // "张 三"
user.fullName = "李 四";
console.log(user.name); // "李"
console.log(user.surname); // "四"

访问器属性的描述符

当我们使用Object.defineProperty定义访问器属性时,描述符与数据属性有所不同:

let user = {
  name: "张",
  surname: "三"
};

Object.defineProperty(user, 'fullName', {
  get() {
    return `${this.name} ${this.surname}`;
  },
  set(value) {
    [this.name, this.surname] = value.split(" ");
  },
  enumerable: true,  // 是否可枚举
  configurable: true // 是否可配置
});

重要区别:

  • 访问器描述符没有valuewritable
  • 必须提供get和/或set方法

高级应用技巧

数据验证

getter和setter非常适合用于数据验证:

let user = {
  get age() {
    return this._age;
  },
  
  set age(value) {
    if (value < 0 || value > 120) {
      throw new Error("年龄必须在0到120之间");
    }
    this._age = value;
  }
};

user.age = 25; // 正常
user.age = 150; // 抛出错误

计算属性

getter可以用来创建基于其他属性的计算属性:

let rectangle = {
  width: 10,
  height: 5,
  
  get area() {
    return this.width * this.height;
  }
};

console.log(rectangle.area); // 50

向后兼容

访问器属性在维护API兼容性方面非常有用。例如,当我们需要改变内部实现但保持外部接口不变时:

// 旧版本
function User(name, age) {
  this.name = name;
  this.age = age;
}

// 新版本
function User(name, birthday) {
  this.name = name;
  this.birthday = birthday;
  
  Object.defineProperty(this, "age", {
    get() {
      return new Date().getFullYear() - this.birthday.getFullYear();
    }
  });
}

最佳实践

  1. 命名约定:通常使用下划线前缀(如_propertyName)表示内部属性
  2. 单一职责:保持getter和setter简单,避免复杂逻辑
  3. 一致性:如果一个属性有setter,通常也应该有getter
  4. 性能考虑:频繁计算的属性值可以考虑缓存结果

常见误区

  1. 无限递归:在setter中不小心再次设置相同属性会导致堆栈溢出

    set name(value) {
      this.name = value; // 错误!会导致无限递归
    }
    
  2. 混合使用:不能在同一属性描述符中同时使用valueget/set

    // 错误示例
    Object.defineProperty({}, 'prop', {
      get() { return 1; },
      value: 2
    });
    

通过合理使用getter和setter,我们可以创建更灵活、更健壮的对象接口,同时保持代码的清晰性和可维护性。

zh.javascript.info 现代 JavaScript 教程(The Modern JavaScript Tutorial),以最新的 ECMAScript 规范为基准,通过简单但足够详细的内容,为你讲解从基础到高阶的 JavaScript 相关知识。 zh.javascript.info 项目地址: https://gitcode.com/gh_mirrors/zh/zh.javascript.info

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喻季福

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值