【发布时间】:2013-10-10 10:29:47
【问题描述】:
Object.freeze 或 Object.seal 的反义词是什么?有没有一个函数有 detach 之类的名字?
【问题讨论】:
-
游戏Return True to Win有三个关于解冻冻结物体的问题。但我还没有找到任何答案! (见“解冻”questions here,但也有剧透)
标签: javascript
Object.freeze 或 Object.seal 的反义词是什么?有没有一个函数有 detach 之类的名字?
【问题讨论】:
标签: javascript
没有办法做到这一点,一旦对象被冻结,就无法解冻它。
冻结对象是锁定的最终形式。一旦一个对象 已被冻结,无法解冻 - 也无法以任何方式篡改 方式。这是确保您的对象保持不变的最佳方式 就像你离开他们一样,无限期
【讨论】:
Object.freeze(obj); thirdPartyRoutine(obj); Object.unfreeze(obj); /*continue using obj*/
freeze(锁定)函数还可以返回 key 所需的 key(解锁)它。
我认为你可以做到,使用一些技巧:
代码在这里:
var obj = {a : 5};
console.log(obj); // {a: 5}
Object.freeze(obj);
obj.b = 10; // trying to add something to obj var
console.log(obj); // output: {a: 5} -> means its frozen
// Now use this trick
var tempObj = {};
for(var i in obj){
tempObj[i] = obj[i];
}
console.log(tempObj); // {a: 5}
// Resetting obj var
obj = tempObj;
console.log(obj);// {a: 5}
obj.b = 10; // trying to add something to obj var
console.log(obj); // output: {a: 5, b: 10} -> means it's not frozen anymore
注意:记住一件事,不要做tempObj = obj,那它就行不通了,因为tempObj也被冻结在那里。
【讨论】:
obj != tempObj - 它们的签名不再相同。
obj,但仅在本地范围内。 p.s.我个人喜欢对象无法解冻。
Object.unfreeze=function(o){
var oo=undefined;
if( o instanceof Array){
oo=[];var clone=function(v){oo.push(v)};
o.forEach(clone);
}else if(o instanceof String){
oo=new String(o).toString();
}else if(typeof o =='object'){
oo={};
for (var property in o){oo[property] = o[property];}
}
return oo;
}
var obj={a:1,b:2}
// {a:1,b:2}
obj.c=3;
//{a:1,b:2,c:3}
Object.freeze(obj)
//{a:1,b:2,c:3}
obj.d=5;
//Error: Read only object
obj=Object.unfreeze(obj)
//{a:1,b:2,c:3}
obj.d=5;
//{a:1,b:2,c:3,d:5}
var tab=[1,2,3]
//[1,2,3]
tab.push(4)
//[1,2,3,4]
Object.freeze(tab);
//[1,2,3,4]
tab.push(5)
// Error : Ready only object
tab=Object.unfreeze(tab);
//[1,2,3,4]
tab.push(9)
//[1,2,3,4,9]
【讨论】:
Object.assign 是更好的选择。然而,副本/克隆也不是我想要的,
您无法解冻冻结的对象。
但是,您可以通过将 Object.freeze 方法重写为无操作,使讨厌的库在未来无法冻结任何内容:
Object.freeze = function(obj) { return obj; }; // just return the original object
在大多数情况下,这就足够了。只需在加载库之前运行上面的代码,它就不能再冻结任何东西。 ; )
编辑:某些库(例如immer@7.0.7)会出现问题,除非在调用Object.freeze(obj) 后Object.isFrozen(obj) 返回true。
因此,以下是阻止对象冻结的更安全方法:(原语检查是因为如果您传入原语,WeakSet 会出错)
const fakeFrozenObjects = new WeakSet();
function isPrimitive(val) {
return val == null || (typeof val != "object" && typeof val != "function");
}
Object.freeze = obj=>{
if (!isPrimitive(obj)) fakeFrozenObjects.add(obj);
return obj;
};
Object.isFrozen = obj=>{
if (isPrimitive(obj)) return true;
return fakeFrozenObjects.has(obj);
};
【讨论】:
Object.freeze 的工作方式是有原因的。
您不能解冻(解冻)对象,但如果对象只是基元的集合(没有函数或类),您可以像这样获得对象的解冻克隆:
const unfrozenObj = JSON.parse(JSON.stringify(frozenObj));
【讨论】:
根据答案和 cmets,似乎人们在需要对冻结对象进行变异时会找到此帖子。说“那是不可能的”虽然准确,但并不是很有帮助。
考虑到这一点,这是我根据 2014 年的 @Abdennour TOUMI 回答提出的现代变体
function unfreeze(obj) {
if (Object.isFrozen(obj)) {
return Object.assign({}, obj);
}
return obj;
}
这是一个如何使用它的示例:
let myObj = { one: "1", two: "2", three: "3" };
Object.freeze(myObj);
// error
// myObj.one = "4";
// succeeds
myObj = unfreeze(myObj);
myObj.one = "4";
【讨论】:
在 FF 52 中测试:
就冻结对象的(符号)“父”对象(它被符号引用,除了/除了代码的其他部分对同一对象的其他符号引用之外/之外)不冻结(如窗口) , 仍然可以通过 delete-operator 删除它, - 比如:
删除window.tinymce;
即使 window.tinymce 在之前被 Object.freeze(window.tinymce) 冻结; (否则,“父级”本身会变成某种“冻结”,因为它包含不可破坏的对象引用,这会使未冻结的父级的符号不可删除......)
只要在删除/删除之前已经制作了原始对象的副本/克隆/重建/自己的版本/,它就摆脱了/没有/原始限制(冻结、可扩展性、可配置性、可写性等) on),可以将对该副本/克隆/重建/自己的版本/的引用放置/分配到原始符号位置,- 就像这样:
window.tinymce = the_copy_clone_reconstruction_own_version_object;
确保在您的解决方法代码完成后,该“copy_clone_reconstruction_own_version_object”在全局范围内不会被删除! [实际上,对象本身应该被删除/它的内存被释放/仅当对它的最后一个引用已从任何范围中删除时, - 一段时间后,由于垃圾收集,但我不确定优先级高于'函数完成 - 删除所有本地变量']
未经测试: 此外,其他符号引用可能指向原始的、冻结/受限的对象, - 像某些东西,它被设置为
myobj.subobj=window.tinymce;
在您的操作开始之前。
这样的东西 (myobj.subobj) 可能会(试一试!)而且指向冻结的原始文件 (?)。
下一个概念: 未测试!
如何使用“代理”功能来包装冻结/密封或其他受限(可扩展性,...)对象的 value-get/-set 和其他行为(函数,...)?
在全球范围内创建,例如
p = 新代理(目标,处理程序);
或者
window.p = 新代理(目标,处理程序);
// 其中 target 是为拦截/挂钩/监控而包装的对象,例如“window.tinymce”
proxy-topic 的 mdn-doc 说,被包装对象的限制(冻结,...)被考虑在内,但这可能是指核心/原始对象本身(由代理包装)并且最终可能不会引用代理所做的模仿......
范围规则可能如上所述适用...
【讨论】:
我也遇到过这个问题。为了修复它,我使用 JavaScript JSON API 来解冻我的对象:const unfreezeObject = JSON.parse(JSON.stringify(freezeObject))。之后,我做了所有我需要的突变。
【讨论】:
{ ...item }。
聚会晚了一点,但您也可以在可变变量 (let) 中创建一个对象,并在需要重置时将原始对象重新分配给该变量。
例如:
let obj = { objProp: "example" };
if (condition) {
Object.freeze(obj);
}
else {
obj = { objProp: "example" };
}
【讨论】:
您可以使用展开运算符解冻数组。
//let suppose arr is a frozen array i.e. immutable
var arr = [1, 2, 3];
//if arr is frozen arr you cannot mutate any array referring to it
var temp = arr;
temp.push(4); //throws an error "Cannot modify frozen array elements"
//here mutableArr gets the elements of arr but not reference to it
//hence you can mutate the mutableArr
var mutableArr = [...arr];
mutableArr.push(4); //executes successfully
【讨论】: