You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript中如何递归冻结对象?是否有语言特性或通用实现方式?

好问题!Object.freeze()本身是浅冻结,只能锁定对象自身的直接属性,不会递归处理嵌套的引用类型(比如你例子里的engine对象),所以才会出现修改嵌套属性依然有效的情况。下面给你讲清楚递归冻结对象的正确实现方式和相关细节:

1. 基础递归冻结实现

我们可以写一个自定义函数,遍历对象的所有可枚举属性,对每个引用类型的属性递归调用冻结,最后再冻结当前对象。

function deepFreeze(obj) {
  // 先处理非对象的情况:如果传入的不是对象或者是null,直接返回
  if (typeof obj !== 'object' || obj === null) {
    return obj;
  }

  // 遍历对象的所有可枚举属性
  Object.keys(obj).forEach(key => {
    const value = obj[key];
    // 递归冻结嵌套的对象/数组
    deepFreeze(value);
  });

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

用你的例子测试:

const engine = {"power": 200};
const car = {"brand": "Fiat", "motor": engine};

// 递归冻结整个car对象及其嵌套对象
deepFreeze(car);

// 现在尝试修改嵌套属性:严格模式下会抛出TypeError,非严格模式下静默失败
car.motor.power = 400;
console.log(car.motor.power); // 输出200,修改无效
2. 更健壮的完善版本

上面的基础版本已经能处理大部分场景,但如果要覆盖更多边界情况(比如不可枚举属性、数组、Symbol属性),可以优化函数:

function deepFreeze(obj) {
  if (typeof obj !== 'object' || obj === null) {
    return obj;
  }

  // 先处理数组的情况(数组也是对象,需要冻结其元素)
  if (Array.isArray(obj)) {
    obj.forEach(item => deepFreeze(item));
  } else {
    // 获取所有属性,包括不可枚举和Symbol类型的属性
    Reflect.ownKeys(obj).forEach(key => {
      const value = obj[key];
      // 只对对象类型(排除函数,因为函数一般不需要冻结)递归处理
      if (typeof value === 'object' && value !== null && typeof value !== 'function') {
        deepFreeze(value);
      }
    });
  }

  return Object.freeze(obj);
}

这个版本做了这些优化:

  • 处理数组类型,递归冻结数组的每一个元素
  • 使用Reflect.ownKeys()获取所有属性(包括不可枚举属性和Symbol作为键的属性)
  • 排除了函数类型的属性(如果你的场景需要冻结函数,可以去掉这个判断)
3. 原生语言特性说明

目前JavaScript没有原生的深冻结API,Object.freeze()、Object.seal()、Object.preventExtensions()都是浅操作。所以递归冻结只能通过自定义函数实现,或者使用成熟的工具库(比如Lodash的_.deepFreeze就是深冻结实现,但如果不想引入库,自定义函数是最通用的方式)。

另外要注意:

  • 冻结是不可逆的,一旦对象被冻结,就无法再解冻
  • 在严格模式下,尝试修改冻结对象的属性会抛出TypeError,非严格模式下会静默失败
  • 冻结对象的原型链不会被影响,如果需要冻结原型,需要单独处理

内容的提问来源于stack exchange,提问作者M. Twarog

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:59:17