有没有一个简单的方法来完全冻结对象和它的孩子在Javascript,(深度冻结)?

lnlaulya  于 2023-03-16  发布在  Java
关注(0)|答案(6)|浏览(139)

通常你必须传递一个对象作为参数。访问这些对象的函数是通过引用传递的,并且可以改变原始对象。这取决于情况可能是不想要的结果。那么有没有方法冻结对象呢?我知道Object.freeze()
但它不影响它内部的对象/数组。
例如

a = { arr: [1,2,3]}; 
Object.freeze(a);
a.arr.push(4); // still works
iecba09b

iecba09b1#

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

// 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))
}

tldr;双内衬:

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

q9yhzks02#

你可以这样做一个非常简单的递归解决方案:

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);
z0qdvdin

z0qdvdin3#

如果你看一下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

gudnpqoy

gudnpqoy4#

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
谢谢你:)

np8igboo

np8igboo5#

检出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;
};
cu6pst1q

cu6pst1q6#

另一种方法是使用代理,而不是深度冻结对象,你得到一个禁止写的对象代理:

const deepFreezeProxy = o => o===null || typeof o !== 'object' ? o : new Proxy(o, {
  get(obj, prop) {
    return deepFreezeProxy(obj[prop]);
  },
  set(obj, prop, val, rec) {
    console.warn(`Can not set prop ${prop} on freezed object`)
    return rec;
  }
});

相关问题