Object.freeze
or的反义词是Object.seal
什么?是否有一个名称为 detach 的函数?
10 回答
我认为你可以做到,使用一些技巧:
- 首先创建原始对象的重复临时变量
- 然后将原始变量设置为未定义
- 从临时重置它的值。
代码在这里:
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
那里也被冻结了。
在这里小提琴:http: //jsfiddle.net/mpSYu/
有线解决方案:)
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.freeze 方法重写为无操作,使讨厌的库将来无法冻结任何内容:
Object.freeze = function(obj) { return obj; }; // just return the original object
在大多数情况下,这就足够了。只需在加载库之前运行上面的代码,它就不能再冻结任何东西。; )
编辑:某些库,例如,除非在调用之后返回immer@7.0.7
,否则会出现问题。Object.isFrozen(obj)
true
Object.freeze(obj)
因此,下面是阻止对象冻结的更安全的方法:(原始检查是因为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);
};
您不能解冻(解冻)对象,但如果对象只是基元的集合(没有函数或类),您可以像这样获得对象的解冻克隆:
const unfrozenObj = JSON.parse(JSON.stringify(frozenObj));
根据答案和评论,人们似乎在需要对冻结对象进行变异时会找到此帖子。说“那是不可能的”虽然准确,但并不是那么有帮助。
考虑到这一点,这是我根据 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 中测试:
至于冻结对象的(符号)“父”对象(它被符号引用,除了/除了代码的其他部分对同一对象的其他符号引用之外)不是冻结的(如窗口),一个可以尽管如此,还是由删除操作员删除它,例如:
删除window.tinymce;
即使 window.tinymce 之前已被 Object.freeze(window.tinymce) 冻结;(否则,“父级”本身将成为某种“冻结”,因为它包含不可破坏的对象引用,这将使未冻结父级的符号不可删除......)
只要在删除/删除之前已经制作了原始对象的副本/克隆/重建/自己的版本/,它就摆脱了/没有/原始限制(冻结、可扩展性、可配置性、可写性等),可以将对该副本/克隆/重建/自己的版本/的引用放置/分配到原始符号位置,就像这样:
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 = new Proxy(target, handler); 或 window.p = new Proxy(target, handler);
// 其中 target 是要为拦截/挂钩/监控包装的对象,例如“window.tinymce”
代理主题的 mdn-doc 说,被包装对象的限制(冻结,...)被保留,但这可能指核心/原始对象本身(由代理包装)并最终可能不要指代代理制作的模仿...
如上所述,范围规则可能适用...
我也是这个问题。为了修复它,我使用 JavaScript JSON API 来解冻我的对象:const unfreezeObject = JSON.parse(JSON.stringify(freezeObject))
. 之后,我做了所有我需要的突变。
晚了一点,但您也可以在可变变量 ( ) 中创建一个对象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