88

What is the opposite of Object.freeze or Object.seal? Is there a function that has a name such as detach?

Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
Abdennour TOUMI
  • 87,526
  • 38
  • 249
  • 254
  • The game [Return True to Win](https://alf.nu/ReturnTrue) has three questions about thawing a frozen object. But I am yet to find any answers! (See 'thaw' [questions here](https://github.com/Rafalsky/return-true-to-win), but also spoilers) – joeytwiddle Mar 20 '19 at 03:43

13 Answers13

128

There is no way to do this, once an object has been frozen there is no way to unfreeze it.

Source

Freezing an object is the ultimate form of lock-down. Once an object has been frozen it cannot be unfrozen – nor can it be tampered in any manner. This is the best way to make sure that your objects will stay exactly as you left them, indefinitely

CodingIntrigue
  • 75,930
  • 30
  • 170
  • 176
  • 12
    This is technically correct as far as mutating the existing object. However, you can copy/clone the existing object and mutate it's properties now. See the answer by Andennour TOUMI (http://stackoverflow.com/a/26752410/1251309) for how to accomplish this. – Levi Roberts Jan 02 '15 at 00:15
  • 10
    It would be SWEEEEET if object could be unfrozen as long as the unfreeze call happened in the same scope. This would be HUGE saving for memory usage, to avoid cloning. f.e. `Object.freeze(obj); thirdPartyRoutine(obj); Object.unfreeze(obj); /*continue using obj*/` – trusktr Feb 19 '18 at 19:07
  • Can you tell why they didn't provide a step to unfreeze an object? – badarshahzad Jun 29 '18 at 05:22
  • 6
    Possibly for security issues? What if you had a global object you don't want anyone touching. Freezing them would be pointless if the potential hacker could just do Object.unfreeze(obj) and get around it. – Jaden Baptista Feb 28 '19 at 19:35
  • 1
    If it were there, inevitably your coworkers would use it on objects you were counting on being frozen. These kinds of problems often escape unit tests too. – Eric Haynes Apr 05 '19 at 02:14
  • 5
    For freezing and unfreezing in the same scope, it could make sense for the `freeze` (lock) function to also return a `key` required to `unfreeze` (unlock) it. – Ghost4Man Jan 09 '21 at 14:46
  • It would be useful to have a native `lock` and `unlock` function in the `object` prototype. Same as `freeze`, but reversible. – Luca Fagioli Jul 18 '21 at 06:35
20

I think you can do, using some tricks:

  • First create a duplicate temporary variable of original object
  • then set the original variable to undefined
  • the reset the value of it from the temporary.

Code here:

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

Note: Keep one thing in mind, don't do tempObj = obj, then it won't work because tempObj is also frozen there.

Fiddle here: http://jsfiddle.net/mpSYu/

Ashish Kumar
  • 2,991
  • 3
  • 18
  • 27
  • 5
    I understand what you're getting at. And copying the values is a way to "get around" freezing an object, but at the end of it all `obj != tempObj` - their signatures are no longer the same. – CodingIntrigue Feb 17 '14 at 11:02
  • But, the frozen object can be deleted!! So, this can be an acceptable solution for now. Cloning the frozen object & assign to same reference and after that deleting the frozen one will get us back to old state, with only disadvantage of this cloning it manually. Of course we lost the original one. – vivek_nk Apr 05 '14 at 09:19
  • 4
    @vivek_nk No, it's not the same. Just because the new variable has the same name doesn't mean it's the same reference (pointer address). You overwrote the frozen `obj`, but only in local scope. p.s. I personally like that objects can't be unfrozen. – Alexander Tsepkov Aug 29 '16 at 06:08
  • This has the downside of creating allocating more memory, and if this is something happening in every frame of an animation for example, then it can get "janky". It would be SWEEEEET if objects could be unfrozen as long as the unfreeze call happened in the same scope. Or, maybe, Object.freeze could return an "unfreeze" function that can be passed around carefully (just like Promise resolve and reject functions can be passed around carefully). – trusktr Feb 19 '18 at 19:10
  • This is not unfreeze but just making copy of original object to tempObj and then reassign obj variable to that tempObj. In other words original obj is now pointing to new reference. Proof for this is that obj and tempObj logs the same after changing obj. You could achieve this more simple without for loop just using var tempObj = {...obj}; obj = tempObj; – Dalibor Jan 21 '21 at 20:58
  • What about if obj was declared const? – Valentino Miori Nov 19 '21 at 08:55
14

Wired solution :)

 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;
 }

Best Practices :


 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]
Abdennour TOUMI
  • 87,526
  • 38
  • 249
  • 254
  • 2
    This should be the accepted answer. Although the other answer is technically correct, this accomplishes the OP's task. – Levi Roberts Jan 02 '15 at 00:16
  • 52
    This does not unfreeze, this copies the object, entirely different thing – Willem D'Haeseleer Nov 02 '16 at 08:10
  • 5
    for the record, all of the answers to this question are wrong, and involve a NEW copy that outscopes the still frozen object... – Leathan Aug 09 '17 at 23:05
  • This is a hack, and will fail in a bunch of different cases. – trusktr Feb 19 '18 at 19:12
  • 1
    If this is a copy of the object, then the spread operator or the `Object.assign` are better option. However a copy/clone is not what I'm looking for either, – ghiscoding Feb 20 '20 at 23:31
  • this is not working for properties which have "enumerable: false" as their descriptor. – milad Sep 12 '20 at 19:46
  • https://codesandbox.io/s/dry-flower-o3c3e?file=/src/index.js fixed it a bit to correctly work with null, undefined, Date and to also deeply unfreeze instead of unfreeze only first level – Yuri Scarbaci Nov 17 '20 at 17:17
  • 1
    Don't ever modify built in classes or prototypes. This is a terrible anti-practice. – jonschlinkert Apr 18 '22 at 17:06
14

You can't unfreeze a frozen object.

You can however make it so pesky libraries can't freeze anything in the future, by overriding the Object.freeze method to be a no-op:

Object.freeze = function(obj) { return obj; }; // just return the original object

In most cases this is enough. Just run the code above before the library is loaded, and it can no longer freeze anything. ; )


EDIT: Some libraries, such as immer@7.0.7, have issues unless Object.isFrozen(obj) returns true after Object.freeze(obj) is called.

The below is thus a safer way of blocking object-freezing: (the primitive checks are because WeakSet errors if you pass in primitives)

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);
};
Venryx
  • 15,624
  • 10
  • 70
  • 96
  • 1
    This seems reasonable to me, like a reverse shim. Why was this downvoted? – amay0048 Jan 16 '17 at 12:19
  • 19
    @amay0048 A shim *adds* behaviour. This *removes* existing behaviour. This is a terrible idea and should definitely not be used in production. `Object.freeze` works the way it does for a reason. – CodingIntrigue Jan 31 '17 at 08:09
  • 3
    It is a terrible idea to use a shim that removes behaviour in production. on the other hand, if you want to hack, you can do whatever you want to achieve your goal. – mjz19910 May 10 '17 at 19:26
  • 2
    You could extend the function override by checking for hallmarks of the object you wish to unfreeze, so it never gets frozen in the first place. Other objects can be frozen still. – Mike de Klerk Oct 04 '17 at 06:30
  • 1
    This really doesn't have much to do with the original post. It's probably better to deal with the "pesky" library in the way their interface suggests. I'm willing to assume stuff gets frozen for a reason. This is likely to cause more problems than it solves. You may get a badge for deleting your own answer.... ;-) – theUtherSide Feb 14 '18 at 23:13
  • 1
    This actually helps me out in unit tests, where hacky stuff is more than welcome... – Kristonitas Feb 10 '21 at 11:27
5

You cannot unfreeze (thaw) an object, but if the object is simply a collection of primitives (no functions or classes), you can get a thawed clone of the object like this:

const unfrozenObj = JSON.parse(JSON.stringify(frozenObj));
joeytwiddle
  • 29,306
  • 13
  • 121
  • 110
  • 3
    I wonder if you can count this as unfreezing. You are essentially creating a new object, frozen object is still immutable – Deepak Jha May 11 '19 at 04:43
2

Based on the answers and comments it seems that people find this post when they need to mutate a frozen object. Saying "that's impossible" while accurate, is not all that helpful.

With that in mind here's the modern variation I came up with based on @Abdennour TOUMI answer from 2014

function unfreeze(obj) {
  if (Object.isFrozen(obj)) {
    return Object.assign({}, obj);
  }
  return obj;
}

Here's an example on how to use it:

let myObj = { one: "1", two: "2", three: "3" };
Object.freeze(myObj);
// error
// myObj.one = "4";
// succeeds
myObj = unfreeze(myObj);
myObj.one = "4";

Michael Sorensen
  • 1,850
  • 12
  • 20
  • This does not unfreeze the object. It just creates a copy, like all the other answers. Also, saying the the other comments are "accurate but unhelpful" is actively useless. If someone wanted to make it so that 1+1=3 and the comments said that was impossible, would you also say "accurate but unhelpful"? It's just not sensible. You can't unfreeze and object and you can't add 1 to itself to get 3. End of story. The only truly helpful thing would be to help someone solve their actual problem in a way that doesn't involve unfreezing objects (or changing arithmetic), which this answer doesn't do. – siride Jan 19 '22 at 13:20
  • 1
    @siride I mean it kind of would be both accurate, and unhelpful for 27 people to all give the same answer that 1+1=3 cannot be true. A comment or upvote on an existing answer should suffice. – Triforcey Mar 17 '22 at 22:22
0

Tested in FF 52:

As far as the frozen-object's (symbolic) 'parent'-object (where it is symbolically referenced by, beside/apart from other symbolic references in other parts of code to the same object) is NOT FROZEN (like window), one can delete it nonetheless by the delete-operator, - like:

delete window.tinymce;

even if window.tinymce had been frozen BEFORE by Object.freeze(window.tinymce); (otherwise the 'parent' would become some kind of "frozen" itself, as containing a non-destroyable object-reference, that would make the symbol of the NOT-frozen parent un-deletable ...)

As far as one has a copy/clone/reconstruction/own version/ of the original object already made before deletion/removal, which got rid/has none/ of the original restrictions (frozen, extensibility, configurability, writeability and so on), one can put/assign a reference to that copy/clone/reconstruction/own version/ to the original symbolic place, - like that way:

window.tinymce = the_copy_clone_reconstruction_own_version_object;

Make sure to have that "copy_clone_reconstruction_own_version_object" in the global scope for not being dropped after Your workaround-code has finished! [Actually the object itself should be dropped/it's memory freed/ just and only when the very last reference to it has been removed from any scope, - some time later, due to-garbage collection, but I'm not sure about the precedence higher than the 'function finished - drop all local vars']

NOT tested: Other symbolic references MAY point to the original, frozen/restricted, object furthermore, - like something, which was set as

myobj.subobj=window.tinymce;

before Your operations began.

Stuff like that (myobj.subobj) will probably (give it a try!) furthermore point to the frozen original (?).

next notion: NOT tested!

What about to use the 'proxy'-feature to wrap value-get/-set and other behaviour (functions, ...) of a frozen/sealed or otherwise restricted (extensibility, ...) object? Created at GLOBAL scope like p = new Proxy(target, handler); or window.p = new Proxy(target, handler);
// where target is the object to wrap for interception/hooking/monitoring, as for instance "window.tinymce"

The mdn-doc for the proxy-topic says, that restrictions (frozen, ...) of the wrapped object are kept regarded, but that could refer to the core-/original-object itself (wrapped by the proxy) and might eventually NOT refer to the mimic made by the proxy ...

Scope-rules might apply as mentioned above ...

dos
  • 9
  • 2
0

I was issue that problem too. TO fix it, I used JavaScript JSON API to unfreeze my object: const unfreezeObject = JSON.parse(JSON.stringify(freezeObject)). After, I did all mutations I needed.

Abbah
  • 131
  • 1
  • 5
  • manual (preferred) or lodash deepClone is a better option. JSON.parse(JSON.stringify(...)) is a flawed way to perform a deep copy. Also, unless you did a deep freeze (recursively applying freeze), a shallow copy `{ ...item }` may be all that is needed. – TamusJRoyce Oct 17 '20 at 04:56
0

A little late to the party, but you can also create an object in a mutable variable (let), and reassign the original object to the variable when you need to reset it.

For example:

let obj = { objProp: "example" };

if (condition) {
    Object.freeze(obj);
}
else {
    obj = { objProp: "example" };
}
thetipsyhacker
  • 1,402
  • 4
  • 18
  • 39
0

I think that if you wanted to keep the original object, but still have unfrozen behaviour, then the only logic still left would be to create a subclass with the same behaviour of the original object, and then internal to the subclass, you would override the behaviour of the existing object by creating accessors that are mutable, which override the ones you want to change.

This way, if you still want the original variable/object alive for some strange reason, or to keep the rest of the system consistent, then you can leave it alone, but have the benefit of its existing behaviour while using the subclass version inheriting directly from the original without necessarily redoing the original parent object. I cannot see how trying the impossible or the illogical seems to be such a desirable thing. You can't have your cake, eat it, then want to still have all of the original cake left, unless you subclass...

Otherwise you are just being impossible.

Raoul
  • 1
  • 1
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community May 18 '22 at 11:52
0

A very simple and very fast map (because cloning and freezing is time consuming). You can extend it and add deep converting and merging from a regular js object or some other methods.

function IMap(key, value) {
  let frozen = false;

  this.lock = function lock() {
    frozen = true;
    return this;
  };

  this.unlock = function unlock(password) {
    if (!password) {
      throw Error("Empty IMap key.");
    }
    if (password === key) {
      frozen = false;
    } else {
      throw Error(`Wrong IMap unlock key.`);
    }
    return this;
  };

  this.set = function set(prop, val) {
    if (!frozen) {
      value[prop] = val;
    } else {
      throw TypeError("IMap is locked.");
    }
    return this;
  };

  this.get = function get(prop) {
    return value[prop];
  };
}

export function iMap(password, source) {
  return new IMap(password, source);
}

usage:

const item = iMap('your-password',{ something: 'value' });
item.lock();
item.set('something',5); // throws an error
item.unlock('your-password').set('something',5).lock(); // ok
neuronet
  • 1,139
  • 8
  • 19
0

You can use slice() function

this.nonFrozenArray = frozenArray.slice()

Example:

    myarray: any[] = []; 
    ngAfterViewInit(): void { this.myService.getDataFromServer(this.id)
      .then(result => {
        console.log('Object.isFrozen = ' + Object.isFrozen(result.data.serverFrozenArray));
        this.myarray = result.data.serverFrozenArray.slice();
console.log('Object.isFrozen = ' + Object.isFrozen(this.myarray));
      })
      .catch(error => {
        console.log(error);
      });
  }
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Apr 21 '23 at 14:13
-2

You can unfreeze an array by using spread operator.

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