前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库class getter setter 与属性描述符的关系
JavaScript对象与原型

class 里的 getter/setter 和普通方法有什么区别?和描述符里的 get/set 是一回事吗?

普通方法要 t.toF() 这样调用,getter 写成 t.f 读属性就会自动执行,setter 在 t.f = 212 赋值时自动执行。本质上 class 里的 get f() 就是在原型上定义了一个访问器属性,描述符里的 get 和 set 就是这两个函数,和 Object.defineProperty 定义出来的是同一种东西。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#对象与原型
先看核心答案读代码示例
理解线索

访问器属性的三种写法

  1. class 里的 get定义在原型上,不可枚举,可配置
  2. 对象字面量里的 get定义在对象自身,可枚举,可配置
  3. Object.defineProperty位置由你决定,没写的特性默认全是 false

只定义了 get 没定义 set 的属性,赋值是否报错看写赋值语句的代码:在 ES 模块或 class 方法里是严格模式,会抛 TypeError;普通脚本里静默失败。

核心回答

先记住这个答案

区别在调用方式和存放位置。普通方法 toF() 是一个值为函数的数据属性,要写 t.toF() 调用;getter 和 setter 伪装成普通属性,读 t.f 就调用 getter,写 t.f = 212 就调用 setter。class 里的 get f() 和 set f() 会在 Temperature.prototype 上定义一个访问器属性,它的描述符是 { get, set, enumerable: false, configurable: true },和用 Object.defineProperty 定义的访问器是同一种东西,只是 class 语法帮你把 enumerable 和 configurable 设好了。

  • getter 读属性时调用,普通方法要手动加括号调用
  • class 的 getter 定义在原型上,不在实例上
  • 访问器描述符有 get、set 等字段
  • 只写 getter 不写 setter,赋值在严格模式下抛错

看代码:getter 像属性,方法像函数

用摄氏度和华氏度换算做例子,实例里只存摄氏度,华氏度通过 getter 算出来。

读写访问器并查看描述符JavaScript
class Temperature {
  constructor(c) {
    this._c = c
  }
  get f() {
    return this._c * 1.8 + 32 // 读 t.f 时自动调用
  }
  set f(value) {
    this._c = (value - 32) / 1.8 // 执行 t.f = 212 时自动调用
  }
  toF() {
    return this._c * 1.8 + 32 // 普通方法,要加括号调用
  }
}

const t = new Temperature(0)
console.log(t.f, t.toF())
t.f = 212
console.log(t._c, Object.keys(t).join())

const d = Object.getOwnPropertyDescriptor(Temperature.prototype, 'f')
console.log(typeof d.get, typeof d.set, d.enumerable, d.configurable)
console.log(Object.hasOwn(t, 'f'))
查看输出与解释
32 32
100 _c
function function false true
false

第二行说明 t.f = 212 并没有在实例上新建一个 f 属性,而是调用了 setter,改的是 _c。实例自身的键只有 _c。第三行就是答案的核心:原型上的 f 是访问器属性,描述符里没有 value 和 writable,只有 get 和 set。最后一行再确认一次,f 不在实例上。

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

属性分两种。数据属性存一个值,描述符有 value 和 writable;访问器属性不存值,描述符有 get 和 set 两个函数。两种属性都有 enumerable 和 configurable。一个属性只能是其中一种,同时写 value 和 get 会抛 TypeError。

普通方法属于数据属性,只不过值碰巧是函数。所以 t.toF 拿到的是函数本身,而 t.f 拿到的是 getter 的返回值,你没有办法通过 t.f 拿到 getter 函数,只能通过描述符拿。

什么时候用 getter 而不是方法

getter 适合「看起来是属性、实际需要计算」的场景,比如派生值 fullName、area,或者给内部字段加一层只读外壳。调用方不用关心它是存的还是算的,以后把存储字段改成计算字段也不用改调用处。

但 getter 应该便宜、没有副作用。每次读取都会重新执行,如果里面有耗时计算、网络请求,或者每次返回新对象,调用方很容易在循环里无意中重复触发。这类逻辑写成方法更诚实,括号本身就在提醒「这里会做事」。Vue 的 computed 就是在 getter 的基础上加了缓存,解决的正是重复计算的问题。

回答前,多想一步

容易答错的地方

以为 getter 定义在实例上
class 里的 getter 在原型上,所有实例共享。Object.keys(t)、JSON.stringify(t) 都看不到它,要序列化得自己写 toJSON。对象字面量里的 getter 才在对象自身,而且是可枚举的。
在 setter 里给同名属性赋值
set f(v) { this.f = v } 会再次触发 setter,无限递归直到栈溢出。要把值存到另一个名字上,比如 _f 或者私有字段 #f。
以为 Object.defineProperty 的默认值和 class 一样
Object.defineProperty(obj, 'f', { get() {} }) 没写的特性全部默认为 false,既不可枚举也不可配置,之后不能删也不能重新定义。class 的 getter 默认可配置。
试着用自己的话回答

面试官还会怎么问?

实例上已经有同名数据属性,getter 还会生效吗?

不会。读属性时先找实例自身,找到数据属性 f 就直接返回,不会继续到原型上找 getter。常见于类字段写了 f = 0,同时又定义了 get f(),字段会在实例上把 getter 挡住。

只有 getter 没有 setter,赋值会怎样?

赋值找到的是原型上 set 为 undefined 的访问器,写入失败。严格模式下抛 TypeError,非严格模式静默失败。ES 模块和 class 的方法体都是严格模式,所以现代项目里通常会直接看到报错。

静态 getter 放在哪里?

static get count() 定义在类本身,也就是构造函数对象上,用 Temperature.count 访问,实例访问不到。

从一道题,走向一组知识

把知识连起来

对象与原型

Object.is 和 === 有什么区别?NaN 和 +0、-0 怎么比?

getter 每次读取都会重新执行,返回新对象时两次读取用 === 比较会是 false,可以顺带复习引用比较。

对象与原型

Symbol.hasInstance 是怎么改写 instanceof 结果的?

static [Symbol.hasInstance] 也是在类上定义特殊成员,和 get、set 一样是 class 语法生成描述符的例子。

参考资料

  • JavaScript:对象与原型参考资料

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 看代码:getter 像属性,方法像函数
  3. 访问器属性和数据属性的区别
  4. 什么时候用 getter 而不是方法
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑