首页 > 解决方案 > 如何在不改变原始对象的情况下创建对象的深度冻结版本?

问题描述

假设我们有以下对象:

"use strict"; // To trigger errors on frozen objects mutation attempts

const myObj = {
  rootProp1: {
    leafProp1: "hello",
    leafProp2: "world",
  rootProp2: "!",
};

当使用“经典”Object.freeze方法时,我们只冻结对象的根属性:

const frozen = Object.freeze(myObj);

frozen.rootProp2 = "?"; // error --> OK
delete frozen.rootProp1; // error --> OK
frozen.extraRootProp = "how are you?"; // error --> OK
frozen.rootProp1.leafProp1 = "hi"; // NO ERROR --> I don't want this

为了深度冻结对象,我们可以使用这样的方法

const deepFrozen = deepFreeze(myObj);

deepFrozen.rootProp1.leafProp1 = "hi"; // error --> OK
myObj.rootProp2 = "?"; // ERROR --> I don't want this

但这对我来说仍然是一个问题:我想要一个可以返回对象的冻结版本而不冻结原始对象的函数(我正在尝试学习函数式编程,所以我想要尽可能少的突变)。怎么做?

标签: javascriptobjectimmutability

解决方案


在 ECMAScript 2018 (ES9) 中,感谢扩展运算符,可以使用这个简单的函数:

const deepFreeze = (obj) => typeof obj === "object"
    ? Object.freeze({
        ...Object.entries(obj).reduce(
          (prev, [key, value]) => ({
            ...prev,
            [key]: value ? deepFreeze(value) : value,
          }),
          {}
        ),
      })
    : typeof obj === "function" ? Object.freeze(obj) : obj;

推荐阅读