前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
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 热点
旧版
首页程序员面试题库Reflect.set 与普通赋值行为区别
JavaScript对象与原型

Reflect.set 和直接用等号赋值,有什么不一样?

Reflect.set(obj, key, value) 和 obj[key] = value 执行的是同一套写入逻辑。区别有两点:Reflect.set 用返回值 true 或 false 告诉你写没写成功,赋值则是严格模式抛 TypeError、非严格模式静默失败;Reflect.set 还能多传一个 receiver,决定 setter 里的 this 指向谁。

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

写入失败时的三种表现

  1. 非严格模式赋值什么都不发生,也不报错,代码继续往下走
  2. 严格模式赋值抛出 TypeError,需要 try...catch 才能兜住
  3. Reflect.set返回 false,调用方自己决定怎么处理

赋值表达式本身的值永远是等号右边的值,(frozen.x = 2) 得到的是 2,不能用它判断写入是否成功。

核心回答

先记住这个答案

Reflect.set 和普通赋值走的是同一个内部写入流程,查原型链、调 setter、检查属性是否可写,这些行为完全一样。不同点在于结果怎么告诉你:Reflect.set 返回布尔值,写入失败就返回 false;普通赋值失败时,严格模式下抛 TypeError,非严格模式下什么都不发生。另外 Reflect.set 的第四个参数 receiver 可以指定 setter 执行时的 this,这是它在 Proxy 里被大量使用的原因。

  • 两者底层写入逻辑相同,都会触发 setter
  • Reflect.set 失败返回 false,不抛错
  • 赋值失败:严格模式抛错,非严格模式静默
  • receiver 决定 setter 的 this

写入失败时谁会告诉你

拿一个冻结的对象分别试试两种写法。示例运行在非严格模式下。

返回值的区别JavaScript
const frozen = Object.freeze({ x: 1 })
const r1 = (frozen.x = 2) // 赋值表达式的值就是右边的 2
const r2 = Reflect.set(frozen, 'x', 2) // 写入失败,返回 false
console.log(r1, r2, frozen.x)

const obj = { x: 1 }
console.log((obj.x = 5), Reflect.set(obj, 'x', 6), obj.x)
查看输出与解释
2 false 1
5 true 6

第一行里 frozen.x 没变,但赋值表达式照样得到 2,看不出失败。Reflect.set 直接返回 false。写入普通对象时,它返回 true,值也确实改了。 如果这段代码在严格模式下跑,frozen.x = 2 会直接抛 TypeError,后面的代码都执行不到。Reflect.set 在两种模式下表现一致,都只返回 false。它唯一会抛错的情况是第一个参数不是对象,比如 Reflect.set(1, 'x', 2)。 写入会失败的情况有这几种:属性不可写、属性是只有 getter 没有 setter 的访问器、对象不可扩展时新增属性,以及原型链上同名属性不可写。最后一种比较隐蔽,对象自己明明没有这个属性,却因为原型上的同名属性只读而写不进去。

receiver 参数改变了什么

赋值 obj.v = 9 时,setter 里的 this 就是 obj。Reflect.set(target, 'v', 9, receiver) 则是在 target 上找属性,但把 receiver 当作 this。

setter 写到了别的对象上JavaScript
const target = {
  _v: 1,
  set v(val) { this._v = val } // this 是 receiver
}
const other = { _v: 0 }
Reflect.set(target, 'v', 9, other)
console.log(target._v, other._v)

const plain = { n: 1 }
const recv = {}
Reflect.set(plain, 'n', 2, recv) // 普通数据属性,值写到 receiver 上
console.log(plain.n, recv.n)
查看输出与解释
1 9
1 2

第一组里 setter 定义在 target 上,但执行时 this 是 other,所以改的是 other._v。第二组 n 是普通数据属性,值同样写到了 recv 上,plain 没变。这就是规范里的规则:写入最终落在 receiver 上,不传 receiver 时默认就是 target 本身。

为什么 Proxy 的 set 陷阱要传 receiver
Proxy 的 set 陷阱签名是 set(target, key, value, receiver),这里的 receiver 通常是代理对象本身,或者继承了代理的对象。在陷阱里写 return Reflect.set(target, key, value, receiver),setter 里的 this 会指向代理,后续读写依然经过代理,响应式系统才能拦截到。直接写 target[key] = value 会让 this 变成原始对象,绕过了代理。而且陷阱必须返回布尔值,严格模式下返回 false 会抛 TypeError,Reflect.set 的返回值正好可以直接用。Vue 3 的 reactive 在 set 陷阱里就是这么写的。
回答前,多想一步

容易答错的地方

以为 Reflect.set 会绕过 setter 或只读检查
它不是「底层直接写内存」的后门,setter 照样触发,只读属性照样写不进去。想跳过 setter 定义一个数据属性,应该用 Object.defineProperty 或 Reflect.defineProperty。
以为赋值失败一定会报错
非严格模式下给只读属性赋值是静默失败的。老项目里的普通脚本不是严格模式,这类 bug 很难发现。ES Module 和 class 内部默认是严格模式,会直接抛错。
用赋值表达式的结果判断成功与否
a.x = 2 这个表达式的值永远是 2,和写入成没成功无关。要判断结果只能用 Reflect.set 的返回值,或者写完再读一次。
试着用自己的话回答

面试官还会怎么问?

Reflect 上的方法和 Object 上的同名方法有什么区别?

主要是失败时的处理方式。比如 Object.defineProperty 失败会抛 TypeError,Reflect.defineProperty 返回 false。另外 Reflect 的方法和 Proxy 的 13 个陷阱一一对应,参数也一致,所以在陷阱里转发默认行为最方便。

在 Proxy 的 set 陷阱里不返回值会怎样?

不返回就等于返回 undefined,会被当作 false。非严格模式下这次写入静默失败,严格模式下抛 TypeError。所以陷阱里一定要把 Reflect.set 的结果返回出去。

原型上有 setter,给子对象赋值会发生什么?

会调用原型上的 setter,this 指向子对象,子对象上不会新增同名属性。这和数据属性不同,原型上是可写的数据属性时,赋值会在子对象上新建一个同名属性,把原型上的遮住。

从一道题,走向一组知识

把知识连起来

对象与原型

怎么创建一个可撤销的 Proxy?撤销之后再访问会怎样?

Reflect.set 最常出现在 Proxy 的 set 陷阱里,可撤销代理撤销后,这类操作全都会抛 TypeError。

对象与原型

Object.seal 和 Object.freeze 有什么区别?各自还允许改什么?

被 freeze 的对象写入会失败,seal 的对象改已有属性却能成功,正好用 Reflect.set 的返回值来验证。

参考资料

  • Reflect.set()

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

本题目录
  1. 先记住这个答案
  2. 写入失败时谁会告诉你
  3. receiver 参数改变了什么
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

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

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