前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
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 热点
旧版
首页程序员面试题库Object.seal 与 Object.freeze 允许的操作区别
JavaScript对象与原型

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

Object.seal 之后不能加属性、不能删属性,但已有属性的值还能改。Object.freeze 更严格,在 seal 的基础上把所有属性都变成只读,值也不能改了。两者都只管第一层,嵌套对象照样能改。

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

三个级别的对象锁

  1. Object.preventExtensions只禁止新增属性,已有属性能删也能改
  2. Object.seal再把所有属性设成 configurable: false,不能删、不能改描述符
  3. Object.freeze再把数据属性设成 writable: false,值也不能改

freeze 管不住访问器属性。对象上有 set 方法的属性,冻结之后调用 setter 照样会执行,setter 里改的是别处的数据。

核心回答

先记住这个答案

Object.seal 让对象不能新增属性、不能删除属性,但已有属性的值还能改。Object.freeze 在它的基础上再进一步,把所有属性都变成只读,值也改不了。可以记成:seal 是把房间门锁上,屋里的东西还能挪;freeze 是连东西都焊死了。两者都只作用于对象第一层,而且在非严格模式下,违规操作不会报错,只是悄悄不生效。

  • seal:不能增删,能改值
  • freeze:不能增删,也不能改值
  • 两者都是浅的,嵌套对象不受保护
  • 严格模式下违规操作可能抛错

用一段代码看清两者的边界

同样一组操作,分别作用在 seal 和 freeze 过的对象上。

增、删、改分别会怎样JavaScript
const sealed = Object.seal({ a: 1 })
sealed.a = 2 // 允许:改已有属性的值
sealed.b = 3 // 静默失败:不能新增
delete sealed.a // 静默失败:不能删除
console.log(JSON.stringify(sealed))

const frozen = Object.freeze({ a: 1, inner: { x: 1 } })
frozen.a = 2 // 静默失败:值也不能改
frozen.inner.x = 2 // 成功:freeze 只管第一层
console.log(frozen.a, frozen.inner.x)

console.log(Object.isSealed(frozen), Object.isFrozen(sealed))

;(function () {
  'use strict'
  try { frozen.a = 3 } catch (err) { console.log(err.name) }
})()
查看输出与解释
{"a":2}
1 2
true false
TypeError

前面几行在非严格模式下执行,失败的赋值和删除都没有报错,结果只能靠打印才看得出来。最后一段加了 'use strict',同样的赋值直接抛 TypeError。ES Module 和 class 内部默认就是严格模式,所以在现代项目里多数时候你会看到报错。 Object.isSealed(frozen) 是 true,说明冻结的对象一定也是密封的。反过来不成立,密封的对象属性还能写,所以不算冻结。

它们实际改了什么:属性描述符

每个属性背后都有一组描述符,其中 writable 控制值能不能改,configurable 控制属性能不能删、描述符能不能再改。对象本身还有一个「可扩展」标记,控制能不能加新属性。

三个方法就是在逐级关掉这些开关。Object.preventExtensions 只关掉可扩展。Object.seal 关掉可扩展,再把每个属性的 configurable 设成 false。Object.freeze 在 seal 的基础上,再把每个数据属性的 writable 设成 false。用 Object.getOwnPropertyDescriptor(sealed, 'a') 打印出来,能直接看到 writable: true, configurable: false。

还有一个细节:seal 之后,你仍然可以把某个属性从 writable: true 改成 false,但反过来改不回去。规范允许不可配置的属性往更严格的方向走一步。

数组也一样
Object.freeze([1, 2]) 之后,push、pop、splice 这类会改数组的方法都会抛 TypeError,而且不管是不是严格模式都会抛,因为这些方法内部用的是会报错的写入方式。密封的数组不能 push,但 arr[0] = 9 可以。
回答前,多想一步

容易答错的地方

以为 freeze 之后对象完全不可变
freeze 是浅的。frozen.inner.x = 2 能成功,因为 inner 这个属性存的是一个引用,冻结的是引用不能换,引用指向的对象没被冻结。要深冻结,得递归地对每个对象属性调用 Object.freeze。
以为赋值失败一定会报错
非严格模式下只是静默失败。老项目里的普通脚本、控制台里直接敲的代码都是非严格模式,赋值「看起来成功了」,数据其实没变,这类问题很难排查。
分不清 seal 和 preventExtensions
preventExtensions 只禁止新增,属性还能删。seal 连删除都禁止了。
试着用自己的话回答

面试官还会怎么问?

怎么实现一个深冻结?

先对当前对象调用 Object.freeze,再遍历 Reflect.ownKeys(obj),遇到值是对象且还没冻结的,就递归处理。用 Object.isFrozen 做判断,顺便能避免循环引用导致死循环。

冻结对象能被解冻吗?

不能,这三个操作都是单向的。想「修改」冻结对象,只能复制一份新的,比如 { ...frozen, a: 2 },得到的新对象是普通对象。

实际项目里什么时候用 freeze?

常量配置、枚举对象,以及强调不可变数据的状态管理。比如 Redux Toolkit 底层的 Immer 会自动冻结它生成的 state,谁直接改 state 就会立刻失败,问题能尽早暴露。Vue 里把大列表数据冻结后再交给响应式系统,Vue 会跳过它,不做深层代理,能省掉不少开销。

从一道题,走向一组知识

把知识连起来

对象与原型

深拷贝和浅拷贝有什么区别?手写深拷贝怎么处理循环引用?

freeze 和浅拷贝一样只处理第一层,想深冻结得像深拷贝那样递归遍历,写法几乎一样。

对象与原型

{ ...obj } 会复制哪些属性?不可枚举的、原型上的会被复制吗?

冻结对象用 ... 展开后得到的是一个普通的新对象,可以随便改,这是绕开冻结做「修改」的常见写法。

参考资料

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

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

本题目录
  1. 先记住这个答案
  2. 用一段代码看清两者的边界
  3. 它们实际改了什么:属性描述符
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

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

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