代码之家  ›  专栏  ›  技术社区  ›  Muhammad Umer

有没有一种简单的方法可以在Javascript中完全冻结对象及其子对象(Deep freeze)?

  •  0
  • Muhammad Umer  · 技术社区  · 5 年前

    通常必须将对象作为参数传递。访问这些对象的函数是通过引用传递的,可以更改原始对象。这取决于情况可能是不想要的结果。有没有办法冻结物体。我知道 Object.freeze()

    但它不影响其中的对象/数组。

    例如

    a = { arr: [1,2,3]}; 
    Object.freeze(a);
    a.arr.push(4); // still works
    
    1 回复  |  直到 5 年前
        1
  •  1
  •   Jack Bashford    5 年前

    您可以创建一个非常简单的递归解决方案,如下所示:

    let a = {
      arr: [1, 2, 3],
      name: "A. Bc"
    };
    
    const deepFreeze = o => {
      for (let [key, value] of Object.entries(o)) {
        if (o.hasOwnProperty(key) && typeof value == "object") {
          deepFreeze(value);
        }
      }
      Object.freeze(o);
      return o;
    }
    
    deepFreeze(a);
    
    try {
      a.arr.push(4);
    } catch(e) {
      console.log("Error: ", e);
    }
    console.log(a);
        2
  •  1
  •   ibrahim tanyalcin    5 年前

    如果你看看 MDN ,其中有一个函数建议使用deepFreeze功能,但它不是堆栈安全的。我个人有一个ES5版本可以异步迭代。对于ES6,沿着这些思路可能有用,但我没有彻底测试:

    function deepFreeze(o,promises,oldestParent){
        promises = promises || [];
        oldestParent = oldestParent || o;
        promises.push(
            Promise.resolve().then(function(){
                Object.values(Object.freeze(o)).forEach(function(d,i){
                    typeof d === "object" && deepFreeze(d,promises,oldestParent);
                });
                return oldestParent;
            })
        );
        return Promise.all(promises).then((a)=>a[0]);
    }
    
    var o = {a:3,b:{test:1,test2:2},c:1};
    deepFreeze(o).then(function(x){console.log(x)}); //o is deep frozen
    

    :我假设对象的属性是可枚举的,如果不是,则使用 getOwnPropertyNames 相反。

        3
  •  1
  •   Muhammad Usman    5 年前
    function deepFreeze(object) {
    
      // Retrieve the property names defined on object
      var propNames = Object.getOwnPropertyNames(object);
    
      // Freeze properties before freezing self
    
      for (let name of propNames) {
        let value = object[name];
    
        object[name] = value && typeof value === "object" ? 
          deepFreeze(value) : value;
      }
    
      return Object.freeze(object);
    }
    
    let a = { arr: [1,2,3]}; 
    deepFreeze(a);
    a.arr.push(4); // TypeError: Cannot add property 3, object is not extensible
    

    (第二个代码[第二个灰色区域]) https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze#What_is_shallow_freeze

        4
  •  0
  •   Rami Jarrar    5 年前

    结账 deep-freeze 它是递归的 Object.freeze()

    下面是他们如何实现的

    function deepFreeze (o) {
      Object.freeze(o);
    
      Object.getOwnPropertyNames(o).forEach(function (prop) {
        if (o.hasOwnProperty(prop)
        && o[prop] !== null
        && (typeof o[prop] === "object" || typeof o[prop] === "function")
        && !Object.isFrozen(o[prop])) {
          deepFreeze(o[prop]);
        }
      });
    
      return o;
    };
    
        5
  •  0
  •   dsharhon    5 年前

    要深度冻结所有可枚举属性(ES2015+):

    // Recursively freeze an object
    const deepFreeze = x => {
      Object.freeze(x)
      Object.values(x).forEach(deepFreeze)
    }
    

    // Recursively freeze an object with circular references
    const deepFreeze = x => {
      Object.freeze(x)
      Object.values(x).filter(x => !Object.isFrozen(x)).forEach(deepFreeze)
    }
    

    如果你 必须深度冷冻任何浅冻物品(稍慢):

    // Recursively deep freeze an object with circular references
    const deepFreeze = (x, frozen = []) => {
      if (frozen.includes(x)) return null
      frozen.push(x)
      Object.freeze(x)
      Object.values(x).forEach(x => deepFreeze(x, frozen))
    }
    

    const deepFreeze = (x, frozen = []) => frozen.includes(x) ||
      frozen.push(Object.freeze(x)) && Object.values(x).forEach(x => deepFreeze(x, frozen))