I just heard about the JavaScript methods freeze
and seal
, which can be used to make any Object immutable.
Here\'s a short example how to u
I wrote a test project which compares these 3 methods:
Object.freeze()
Object.seal()
Object.preventExtensions()
My unit tests cover CRUD cases:
Result:
You can now force a single object property to be frozen instead of freezing the whole object. You can achieve this with Object.defineProperty
with writable: false
as a parameter.
var obj = {
"first": 1,
"second": 2,
"third": 3
};
Object.defineProperty(obj, "first", {
writable: false,
value: 99
});
In this example, obj.first
now has its value locked to 99.
I have created a simple table to compare the below functions and explain the difference between these functions.
Object.freeze()
Object.seal()
Object.preventExtensions()
Object.freeze()
creates a frozen object, which means it takes an
existing object and essentially calls Object.seal()
on it, but it also
marks all “data accessor” properties as writable:false
, so that their
values cannot be changed. - Kyle Simpson, You Don't Know JS - This & Object Prototypes
Object.seal
delete
will return falsewritable
attribute, and their value
attribute if writeable
is true).TypeError
when attempting to modify the value of the sealed object itself (most commonly in strict mode)Object.freeze
Object.seal
does, plus:Neither one affects 'deep'/grandchildren objects. E.g., if obj
is frozen, obj.el
can’t be reassigned, but the value of obj.el
could be modified, e.g. obj.el.id
can be changed.
Sealing or freezing an object may affect its enumeration speed, depending on the browser:
Tests: Sealed objects, Frozen objects.
I was looking at the differences between Freeze and Seal in ECMAScript 5 and created a script to clarify the differences. Frozen creates an immutable object including data and structure. Seal prevents changes to the named interfaces - no adds, deletes - but you can mutate the object and redefine the meaning of its interface.
function run()
{
var myObject = function()
{
this.test = "testing";
}
//***************************SETUP****************************
var frozenObj = new myObject();
var sealedObj = new myObject();
var allFrozen = Object.freeze(frozenObj);
var allSealed = Object.seal(sealedObj);
alert("frozenObj of myObject type now frozen - Property test= " + frozenObj.test);
alert("sealedObj of myObject type now frozen - Property test= " + sealedObj.test);
//***************************FROZEN****************************
frozenObj.addedProperty = "added Property"; //ignores add
alert("Frozen addedProperty= " + frozenObj.addedProperty);
delete frozenObj.test; //ignores delete
alert("Frozen so deleted property still exists= " + frozenObj.test);
frozenObj.test = "Howdy"; //ignores update
alert("Frozen ignores update to value= " + frozenObj.test);
frozenObj.test = function() { return "function"; } //ignores
alert("Frozen so ignores redefinition of value= " + frozenObj.test);
alert("Is frozen " + Object.isFrozen(frozenObj));
alert("Is sealed " + Object.isSealed(frozenObj));
alert("Is extensible " + Object.isExtensible(frozenObj));
alert("Cannot unfreeze");
alert("result of freeze same as the original object: " + (frozenObj === allFrozen).toString());
alert("Date.now = " + Date.now());
//***************************SEALED****************************
sealedObj.addedProperty = "added Property"; //ignores add
alert("Sealed addedProperty= " + sealedObj.addedProperty);
sealedObj.test = "Howdy"; //allows update
alert("Sealed allows update to value unlike frozen= " + sealedObj.test);
sealedObj.test = function() { return "function"; } //allows
alert("Sealed allows redefinition of value unlike frozen= " + sealedObj.test);
delete sealedObj.test; //ignores delete
alert("Sealed so deleted property still exists= " + sealedObj.test);
alert("Is frozen " + Object.isFrozen(sealedObj));
alert("Is sealed " + Object.isSealed(sealedObj));
alert("Is extensible " + Object.isExtensible(sealedObj));
alert("Cannot unseal");
alert("result of seal same as the original object: " + (sealedObj === allSealed).toString());
alert("Date.now = " + Date.now());
}