0

0

JavaScript的Object.freeze方法是什么?怎么用?

畫卷琴夢

畫卷琴夢

发布时间:2025-07-11 18:45:02

|

1014人浏览过

|

来源于php中文网

原创

object.freeze 是 javascript 中用于冻结对象的方法,它阻止添加、删除或修改对象的顶层属性,但对嵌套对象无效。1. 它接收一个对象并返回被冻结的对象;2. 冻结后,属性不可变,严格模式下修改会抛出错误;3. 实现的是浅冻结,嵌套对象仍可被修改。应用场景包括防止配置对象被篡改、提升代码可预测性和调试效率。与 object.seal 和 object.preventextensions 相比,freeze 最严格,seal 不允许增删属性但可修改值,preventextensions 仅阻止新增属性。实现深冻结需递归冻结所有嵌套对象,并注意处理循环引用问题。

JavaScript的Object.freeze方法是什么?怎么用?

Object.freeze 是 JavaScript 提供的一个方法,它能让一个对象变得“冻结”,这意味着你不能再添加新的属性、删除已有属性、修改属性的枚举性、可配置性或写入性,也无法改变其原型。简单来说,一旦对象被冻结,它就不能再被改变了,至少是其第一层属性。

JavaScript的Object.freeze方法是什么?怎么用?

Object.freeze() 方法接收一个对象作为参数,并返回这个被冻结的对象。它的核心作用就是阻止对目标对象进行任何修改。当你尝试对一个冻结的对象进行添加、删除或修改属性的操作时,在严格模式下会抛出 TypeError 错误,在非严格模式下则会静默失败。需要特别注意的是,Object.freeze 实现的是浅冻结。这意味着如果一个对象内部包含其他对象(比如嵌套对象或数组),这些内部的对象本身并不会被冻结,它们仍然是可变的。这是我个人在使用时经常需要注意的一个点,因为有时候我们期望的是深冻结,但 freeze 并不提供这个功能。

const user = {
  name: '张三',
  age: 30,
  address: {
    city: '北京',
    zip: '100000'
  },
  hobbies: ['阅读', '编程']
};

Object.freeze(user);

// 尝试修改冻结对象的属性
user.name = '李四'; // 无效,严格模式下会报错
console.log(user.name); // 输出 '张三'

// 尝试添加新属性
user.gender = '男'; // 无效
console.log(user.gender); // 输出 undefined

// 尝试删除属性
delete user.age; // 无效
console.log(user.age); // 输出 30

// 尝试修改嵌套对象的属性(浅冻结的体现)
user.address.city = '上海'; // 有效!
console.log(user.address.city); // 输出 '上海'

// 尝试修改嵌套数组的元素
user.hobbies.push('旅行'); // 有效!
console.log(user.hobbies); // 输出 ['阅读', '编程', '旅行']

这个例子很直观地展示了 freeze 的浅层特性。对于 user 对象本身,它的直接属性被锁死了,但 user.addressuser.hobbies 内部的内容,还是可以动的。这在处理复杂数据结构时,确实需要多想一步。

立即学习Java免费学习笔记(深入)”;

JavaScript的Object.freeze方法是什么?怎么用?

为什么我们需要冻结对象?它在实际开发中有哪些应用场景?

从我个人的经验来看,冻结对象最直接的价值在于提供数据不可变性。在很多复杂的应用中,尤其是涉及到状态管理或者共享数据时,我们经常会遇到数据被意外修改导致的问题,调试起来非常头疼。Object.freeze 提供了一个简单的机制来防止这种意外。

想象一下,你有一个配置对象,它定义了整个应用的常量或者某个模块的默认设置。如果这个配置对象在应用的某个角落被不小心修改了,可能会导致意想不到的行为。通过 Object.freeze 对其进行冻结,可以有效避免这种“运行时篡改”。

JavaScript的Object.freeze方法是什么?怎么用?
// 示例:冻结配置对象
const APP_CONFIG = Object.freeze({
  API_BASE_URL: 'https://api.example.com',
  TIMEOUT_MS: 5000,
  DEBUG_MODE: false
});

// 尝试修改配置
// APP_CONFIG.API_BASE_URL = 'http://localhost:3000'; // 严格模式下会报错,有效防止修改

// 在函数中传递冻结对象作为参数,确保其不会被函数内部修改
function processData(config) {
  // config.DEBUG_MODE = true; // 无法修改
  console.log('Processing data with config:', config.API_BASE_URL);
}

processData(APP_CONFIG);

此外,在一些函数式编程的范式中,不可变数据是核心理念。虽然 Object.freeze 只是一个浅层实现,但它至少能保证对象顶层属性的稳定。这对于构建更可预测、更易于测试的代码库非常有帮助。当你在调试一个bug,发现某个数据结构的值不对劲时,如果知道它是被冻结的,至少可以排除掉“被意外修改”这个可能性,缩小排查范围。这种确定性,在项目复杂起来的时候,价值真的很大。

Object.freeze与Object.seal、Object.preventExtensions有什么区别

这三个方法都与对象的“可变性”有关,但它们提供的限制程度是不同的,就像是给对象上锁,但锁的级别不一样。

  • Object.preventExtensions(): 这是最宽松的限制。它仅仅是阻止向对象添加新的属性。你仍然可以删除现有属性,也可以修改现有属性的值、枚举性、可配置性或写入性。

    手机在线人工冲值
    手机在线人工冲值

    说明:我不知道这个系统还能用到什么地方!他的运作方式是这样的,客户在其他地方比如掏宝购买了 你得卡,然后在你的网站进行冲值,你得有人登陆并看着后台,如果有人冲值,就会刷出记录,手工冲值完毕后,你得点击 [冲值完毕],客户的页面 就会返回 冲值信息!安装:上传所有文件,倒入(sql.txt)mysql数据库,使用myphpadminphplib 777phplib/sys.php 777phplib

    下载
    const obj1 = { a: 1 };
    Object.preventExtensions(obj1);
    obj1.b = 2; // 无效
    console.log(obj1.b); // undefined
    delete obj1.a; // 有效
    console.log(obj1.a); // undefined
    // obj1.a = 10; // 即使被删除了,这里再赋值也无效,因为preventExtensions后不能添加

    这里有个小陷阱,如果属性已经被删除了,再尝试赋值,那其实是尝试添加新属性,所以也是无效的。

  • Object.seal(): 比 preventExtensions 更进一步。它不仅阻止添加新属性,还阻止删除现有属性。但你仍然可以修改现有属性的值。属性的可配置性(configurable)会被设置为 false,这意味着你不能再删除它们,也不能改变它们的特性(比如从可写变为只读)。

    const obj2 = { a: 1, b: 2 };
    Object.seal(obj2);
    obj2.c = 3; // 无效
    delete obj2.a; // 无效
    obj2.b = 20; // 有效
    console.log(obj2.b); // 20

    在我看来,seal 就像是把对象的“形状”固定下来了,但里面的内容还是可以变的。

  • Object.freeze(): 这是最严格的。它在 Object.seal 的基础上,进一步阻止了修改现有属性的值。所有属性的 writableconfigurable 都会被设置为 false。这意味着,你不能添加、删除或修改任何属性。

    const obj3 = { a: 1, b: 2 };
    Object.freeze(obj3);
    obj3.c = 3; // 无效
    delete obj3.a; // 无效
    obj3.b = 20; // 无效
    console.log(obj3.b); // 2

    总的来说,可以想象成一个渐进的过程:

    • preventExtensions: 不能增加新房间。
    • seal: 不能增加新房间,也不能拆除旧房间,但房间里的家具可以换。
    • freeze: 不能增加新房间,不能拆除旧房间,连房间里的家具都不能换了。

理解这些区别,在选择如何保护对象时,就能做出更合适的决策。我发现很多人容易混淆这几个,但其实它们各自有明确的适用场景。

如何实现一个“深冻结”功能?

前面提到了 Object.freeze 是浅冻结,这在处理包含嵌套对象或数组的数据时,确实是个痛点。如果我真的需要整个数据结构都不可变,那么就需要自己动手实现一个“深冻结”函数。这通常涉及到递归地遍历对象的所有属性。

实现深冻结的核心思路是:遍历对象的所有属性,如果某个属性的值也是一个对象(且不是 null,也不是函数、日期、RegExp等不可冻结的内置对象),那么就递归地对这个内部对象也进行冻结。

function deepFreeze(obj) {
  // 检查对象是否为null或非对象类型,如果是,则直接返回,因为它们无法被冻结
  if (obj === null || typeof obj !== 'object' || obj instanceof Date || obj instanceof RegExp || typeof obj === 'function') {
    return obj;
  }

  // 获取对象的所有属性名
  const propNames = Object.getOwnPropertyNames(obj);

  // 遍历所有属性
  for (const name of propNames) {
    const value = obj[name];

    // 如果属性值是一个对象,并且它不是null,就递归地调用deepFreeze
    if (typeof value === 'object' && value !== null) {
      deepFreeze(value);
    }
  }

  // 最后冻结当前对象
  return Object.freeze(obj);
}

// 示例使用
const complexObj = {
  id: 1,
  data: {
    name: '产品A',
    details: {
      price: 100,
      currency: 'USD'
    }
  },
  tags: ['电子产品', '新上市'],
  config: null, // null 不会报错
  method: () => console.log('hello') // 函数也不会报错
};

const frozenComplexObj = deepFreeze(complexObj);

// 尝试修改顶层属性
frozenComplexObj.id = 2;
console.log(frozenComplexObj.id); // 1

// 尝试修改嵌套对象属性
frozenComplexObj.data.name = '产品B';
console.log(frozenComplexObj.data.name); // '产品A'

// 尝试修改更深层嵌套对象属性
frozenComplexObj.data.details.price = 120;
console.log(frozenComplexObj.data.details.price); // 100

// 尝试修改数组元素
frozenComplexObj.tags.push('热销');
console.log(frozenComplexObj.tags); // ['电子产品', '新上市']

// 尝试修改函数或null
frozenComplexObj.config = {}; // 无效
frozenComplexObj.method = () => console.log('world'); // 无效

实现深冻结时,需要注意循环引用(circular references)的问题。如果对象A引用了对象B,而对象B又引用了对象A,那么简单的递归可能会导致无限循环。不过,对于大多数实际应用场景,这种问题不常见,或者可以通过额外的机制(比如记录已访问过的对象)来避免。我这里提供的 deepFreeze 版本没有处理循环引用,在实际生产环境中,如果数据结构可能存在循环引用,需要引入一个 Set 来记录已经处理过的对象,避免无限递归

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

236

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

458

2024.03.01

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1501

2023.10.24

treenode的用法
treenode的用法

​在计算机编程领域,TreeNode是一种常见的数据结构,通常用于构建树形结构。在不同的编程语言中,TreeNode可能有不同的实现方式和用法,通常用于表示树的节点信息。更多关于treenode相关问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

538

2023.12.01

C++ 高效算法与数据结构
C++ 高效算法与数据结构

本专题讲解 C++ 中常用算法与数据结构的实现与优化,涵盖排序算法(快速排序、归并排序)、查找算法、图算法、动态规划、贪心算法等,并结合实际案例分析如何选择最优算法来提高程序效率。通过深入理解数据结构(链表、树、堆、哈希表等),帮助开发者提升 在复杂应用中的算法设计与性能优化能力。

17

2025.12.22

深入理解算法:高效算法与数据结构专题
深入理解算法:高效算法与数据结构专题

本专题专注于算法与数据结构的核心概念,适合想深入理解并提升编程能力的开发者。专题内容包括常见数据结构的实现与应用,如数组、链表、栈、队列、哈希表、树、图等;以及高效的排序算法、搜索算法、动态规划等经典算法。通过详细的讲解与复杂度分析,帮助开发者不仅能熟练运用这些基础知识,还能在实际编程中优化性能,提高代码的执行效率。本专题适合准备面试的开发者,也适合希望提高算法思维的编程爱好者。

27

2026.01.06

俄罗斯Yandex引擎入口
俄罗斯Yandex引擎入口

2026年俄罗斯Yandex搜索引擎最新入口汇总,涵盖免登录、多语言支持、无广告视频播放及本地化服务等核心功能。阅读专题下面的文章了解更多详细内容。

24

2026.01.28

包子漫画在线官方入口大全
包子漫画在线官方入口大全

本合集汇总了包子漫画2026最新官方在线观看入口,涵盖备用域名、正版无广告链接及多端适配地址,助你畅享12700+高清漫画资源。阅读专题下面的文章了解更多详细内容。

7

2026.01.28

ao3中文版官网地址大全
ao3中文版官网地址大全

AO3最新中文版官网入口合集,汇总2026年主站及国内优化镜像链接,支持简体中文界面、无广告阅读与多设备同步。阅读专题下面的文章了解更多详细内容。

28

2026.01.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
10分钟--Midjourney创作自己的漫画
10分钟--Midjourney创作自己的漫画

共1课时 | 0.1万人学习

Midjourney 关键词系列整合
Midjourney 关键词系列整合

共13课时 | 0.9万人学习

AI绘画教程
AI绘画教程

共2课时 | 0.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号