JavaScript Object.freeze() 详解

1. 核心概念

Object.freeze() 是 JavaScript 中的一个内置方法,用于使对象变为不可变(immutable)状态,防止其属性被修改、添加或删除。

1.1 基本语法

javascript 复制代码
Object.freeze(obj)

2. 功能特性

2.1 主要作用

特性 说明 示例
阻止属性修改 对象属性值不可更改 obj.prop = 'new' 无效
阻止属性添加 无法添加新属性 obj.newProp = 'value' 无效
阻止属性删除 无法删除属性 delete obj.prop 无效
递归冻结 浅层冻结,不递归冻结嵌套对象 obj.nested.value 仍可修改

2.2 返回值

  • 返回原始对象本身(非副本)
  • 冻结后的对象仍然是同一个对象引用

3. 使用示例

3.1 基础用法

javascript 复制代码
const person = {
  name: '张三',
  age: 25,
  city: '北京'
};

// 冻结对象
const frozenPerson = Object.freeze(person);

// 尝试修改属性 - 静默失败(严格模式下报错)
frozenPerson.name = '李四'; // 无效
frozenPerson.newProp = 'test'; // 无效
delete frozenPerson.age; // 无效

console.log(frozenPerson); // { name: '张三', age: 25, city: '北京' }

3.2 严格模式下的行为

javascript 复制代码
'use strict';

const obj = { x: 42 };
Object.freeze(obj);

try {
  obj.x = 9; // TypeError: Cannot assign to read only property 'x' of object
} catch (e) {
  console.error(e.message);
}

3.3 浅层冻结特性

javascript 复制代码
const config = {
  apiUrl: 'https://api.example.com',
  headers: {
    'Content-Type': 'application/json'
  }
};

Object.freeze(config);

// 顶层属性不可修改
config.apiUrl = 'https://new.api.com'; // 无效

// 但嵌套对象的内容仍可修改
config.headers['Content-Type'] = 'text/plain'; // 有效!
console.log(config.headers); // { 'Content-Type': 'text/plain' }

4. 相关方法对比

4.1 对象冻结方法对比

方法 作用 是否递归 示例
Object.freeze() 完全不可变 否(浅层) Object.freeze(obj)
Object.seal() 可修改现有属性,不可增删 Object.seal(obj)
Object.preventExtensions() 不可添加新属性,可修改/删除 Object.preventExtensions(obj)

4.2 方法对比表

特性 freeze() seal() preventExtensions()
修改属性值 ❌ 禁止 ✅ 允许 ✅ 允许
添加新属性 ❌ 禁止 ❌ 禁止 ❌ 禁止
删除属性 ❌ 禁止 ❌ 禁止 ✅ 允许
检查是否可扩展 Object.isFrozen() Object.isSealed() Object.isExtensible()

5. 检测对象状态

5.1 检测方法

javascript 复制代码
const obj = { a: 1 };

console.log(Object.isFrozen(obj)); // false
Object.freeze(obj);
console.log(Object.isFrozen(obj)); // true

const sealedObj = { b: 2 };
Object.seal(sealedObj);
console.log(Object.isSealed(sealedObj)); // true

console.log(Object.isExtensible(obj)); // false

6. 实际应用场景

6.1 配置对象保护

javascript 复制代码
// 应用配置
const APP_CONFIG = Object.freeze({
  API_BASE_URL: 'https://api.example.com',
  TIMEOUT: 5000,
  RETRY_COUNT: 3
});

// 防止意外修改
// APP_CONFIG.API_BASE_URL = 'hacked'; // 无效

6.2 常量定义

javascript 复制代码
// 枚举值
const DIRECTION = Object.freeze({
  UP: 'UP',
  DOWN: 'DOWN',
  LEFT: 'LEFT',
  RIGHT: 'RIGHT'
});

// 使用
function move(direction) {
  if (!Object.values(DIRECTION).includes(direction)) {
    throw new Error('Invalid direction');
  }
  // ... 移动逻辑
}

6.3 函数参数保护

javascript 复制代码
function processUser(user) {
  // 冻结传入的对象,防止函数内部意外修改
  const frozenUser = Object.freeze(user);
  
  // 使用 frozenUser 进行操作
  return {
    ...frozenUser,
    processed: true
  };
}

7. 注意事项

7.1 局限性

  1. 浅层冻结:只冻结对象本身,不递归冻结嵌套对象

  2. 无法冻结不可枚举属性 :如 __proto__constructor

  3. 数组冻结 :数组也是对象,同样适用

    javascript 复制代码
    const arr = [1, 2, 3];
    Object.freeze(arr);
    arr.push(4); // 无效
    arr[0] = 10; // 无效

7.2 性能考虑

  • 冻结操作本身有轻微性能开销
  • 对于大型对象,考虑是否需要完全冻结
  • 在频繁修改的对象上使用冻结会影响性能

8. 最佳实践

8.1 使用建议

  1. 顶层配置对象 :使用 Object.freeze() 保护全局配置
  2. 枚举值定义:创建不可变的枚举对象
  3. 函数参数保护:防止函数内部意外修改传入对象
  4. 状态管理:在 Redux 等状态管理库中保护状态对象

8.2 替代方案

javascript 复制代码
// 使用 Proxy 实现更精细的控制
const createImmutable = (obj) => {
  return new Proxy(obj, {
    set() {
      throw new Error('Object is immutable');
    },
    deleteProperty() {
      throw new Error('Object is immutable');
    }
  });
};

9. 总结

Object.freeze() 是 JavaScript 中实现对象不可变性的重要工具,适用于:

  • 保护配置对象不被意外修改
  • 定义常量枚举值
  • 在函数调用中保护参数对象
  • 实现不可变状态管理

关键要点

  • 冻结是浅层的,不递归冻结嵌套对象
  • 在严格模式下,修改冻结对象会抛出错误
  • 使用 Object.isFrozen() 可以检测对象是否被冻结
  • 对于需要深度冻结的场景,需要递归调用 Object.freeze()
相关推荐
希望永不加班2 小时前
SpringBoot 静态资源访问(图片/JS/CSS)配置详解
java·javascript·css·spring boot·后端
ada0_ada12 小时前
qt模块学习记录
开发语言·qt·学习
liulilittle2 小时前
C++ 无锁编程:单停多发送场景高性能方案
服务器·开发语言·c++·高性能·无锁·原子
m0_738120722 小时前
渗透基础知识ctfshow——Web应用安全与防护(第一章)
服务器·前端·javascript·安全·web安全·网络安全
飞Link2 小时前
大模型时代的“语言编程”:Prompt Engineering (提示词工程) 深度解析与实战指南
开发语言·python·prompt
持续前行2 小时前
通过 npm 下载node_modules 某个依赖 ;例如 下载 @rollup/rollup-linux-arm64-gnu
前端·javascript·vue.js
无限进步_2 小时前
【C++】巧用静态变量与构造函数:一种非常规的求和实现
开发语言·c++·git·算法·leetcode·github·visual studio
Advancer-2 小时前
RedisTemplate 两种序列化实践方案
java·开发语言·redis
郝学胜-神的一滴3 小时前
Socket实战:从单端聊天到多用户连接的实现秘籍
服务器·开发语言·python·网络协议·pycharm