Freeze and Seal in JavaScript
In my last JavaScript article, I talked a bit about mutations in JavaScript and how we can change objects by accident. OK, so this much we know—when I copy an object and then make a change, the object that comes afterward also changes. Why? Because it doesn’t really copy—it’s really a reference. The outcome (whether we intended it or not) is called a mutation in JavaScript. Here’s a quick example just as a reminder:
const object1 = {
property1: 42
};
const object2 = object1;
object2.property1 = 33;
console.log(object1.property1); // 33
It really can be a bit daunting, but that’s how JavaScript works. One solution for dealing with this is to execute deep clone or assign in order to make a copy of the new object.
const object1 = {
property1: 42
};
const object2 = Object.assign({}, object1);
object2.property1 = 33;
console.log(object1.property1); // 42
This of course has its problems, but we won’t get into that. If we created an object and don’t want anything to be able to change it, we can ‘freeze’ that object with Object.freeze. It’s pretty easy, has been around for many years, and is supported by all browsers.
const object1 = {
property1: 42
};
Object.freeze(object1)
const object2 = object1;
object2.property1 = 33;
console.log(object1.property1); // 42
console.log(Object.isFrozen(object1)); // true
What freeze does is essentially is to, well, freeze all of the properties of an object. We can check if an object is frozen using .isFrozen. It’s worth noting that, if we’re talking about a complex object (e.g. an object with a property that is another object) it will be possible to execute a change to the object, just like const.
Here’s another example with an array that I’m freezing. You can see how the mutation is stopped:
const myArray = ['Value', 'Value2', 'Value3'];
Object.freeze(myArray);
function muteMeBaby(someArray) {
someArray[0] = 'newValue';
return someArray;
}
const newArray = muteMeBaby(myArray);
console.log(newArray); // ["newValue", "Value2", "Value3"]
console.log(myArray); // ["newValue", "Value2", "Value3"]
Attempting to change an object found in freeze will cause an error if we are in strict mode.
The truth is, I’ve never seen that much use for freeze. In my opinion, it’s a technique that I wouldn’t be so happy to see in my code for a few reasons. But either way, it’s good to know about it and how it works.
Another way to do something similar is to use Seal. No, not the Grammy Award-winning British R&B singer from the ‘90s. I’m talking about the technique with which I can permanently set all the properties of an object while still allowing their values to be changed.
I think this is a case where an example is worth a thousand words. I created an object and ran seal on it. From that point on, I can change its properties but I can’t add any new ones.
const object1 = {
property1: 42
};
Object.seal(object1)
const object2 = object1;
object2.property1 = 33;
object2.property2 = 11;
console.log(object1.property1); // 33
console.log(object1.property2); // undefined
console.log(Object.isSealed(object1)); // true
console.log(object2.property2); // undefined
This works for all of the objects that have a reference to it—it doesn’t stop all the mutations but it can implement an interface. Again, it’s nice to know about, but I still don’t think it’s all that useful. In object-oriented programming, we often do want to commit to a specific interface. But JavaScript is prototype-based and any attempt to force the logic of a class on it can be problematic. Like I said, good to know, useful in some instances, but for me personally, I don’t see it having a very wide application.
About the author: Ran Bar-Zik is an experienced web developer whose personal blog, Internet Israel, features articles and guides on Node.js, MongoDB, Git, SASS, jQuery, HTML 5, MySQL, and more. Translation of the original article by Aaron Raizen
Recent Stories
Top DiscoverSDK Experts
Compare Products
Select up to three two products to compare by clicking on the compare icon () of each product.
{{compareToolModel.Error}}
{{CommentsModel.TotalCount}} Comments
Your Comment