Object.freeze() Method

It's been a pretty lazy July 4th weekend. The holiday itself was on a Thursday, and while the office was open on Friday, pretty much everyone took the day off or worked from home. On the 4th I went with Tessa and our friend Andrea to a protest against the inhumane border immigration facilities, which took place at the Texas Capitol building. That evening I grilled some burgers and drank a single Budweiser.

I'm getting near the end of that Syntax FM-inspired Array & Object methods series and I'm both excited and nervous to move on. It's been a really good focus for me and I feel like I've learned so much along the way and am already becoming a better developer. While a few non-array method posts have made their way in, and I do have a few other posts sitting on my Trello board that I need to publish, I'm already starting to think about the next thing I'll be taking a deep dive into.

Anyway, today I'm looking at the Object.freeze() method, which takes an object, and does a shallow freeze on it, meaning that its direct properties become unchangeable. It's shallow in that any nested objects within the frozen object can still be changed. It's almost like a thin lacquer coating, where everything on the surface level is frozen, can be accessed but not adjusted or removed, but anything deeper than that is left up for adjustment. Let's take a look.

So of course we can create, change, and delete an object's properties like normal:

const person = {
  name: 'Joey Reyes',
  age: 31,
  twitter: '@codeandtacos',
  hungry: true,
  activities: {
    coding: ['javascript', 'react', 'css'],
    cooking: true,
    cello: true,
  },
};

console.log(person.hungry);
// expected result: true

console.log(person.activities.coding[1]);
// expexted result: 'react'

person.hungry = false;
console.log(person.hungry);
// expected result: false

person.city = 'Austin';
console.log(person.city);
// expected result: "Austin"

delete person.city;
console.log(person.city);
// expected result: undefined

person.activities.coding[2] = 'html';
console.log(person.activities.coding[2]);
// expected result: 'html'

Let's see what happens when we freeze the person object:

const person = {
  name: 'Joey Reyes',
  age: 31,
  twitter: '@codeandtacos',
  hungry: true,
  activities: {
    coding: ['jaascript', 'react', 'css'],
    cooking: true,
    cello: true
  },
};
Object.freeze(person);

person.hungry = false;
console.log(person.hungry);
// expected result: true

person.age = 44;
console.log(person.age);
// expected result: 31

person.city = 'Austin';
console.log(person.city);
// expected result: undefined

delete person.twitter;
console.log(person.twitter);
// expected result: "@codeandtacos"

person.activities.coding[2] = 'html';
console.log(person.activities.coding[2]);
// expected result: "html"

So you see here we can't actually change any of the direct properties, like hungry but we can change the properties within the nested activities object. It should be noted that this fails silently in non-strict mode. In strict mode, it will throw a TypeError:

const person = {
  name: 'Joey Reyes',
  age: 31,
  twitter: '@codeandtacos',
  hungry: true,
  activities: {
    coding: ['javascript', 'react', 'css'],
    cooking: true,
    cello: true
  },
};

Object.freeze(person);

function freeze() {
  "use strict"
  person.hungry = true;
  person.age = 44;
};

freeze();
// expected error: TypeError: Cannot assign to read only property 'hungry' of object '#<Object>'

And of course, since arrays are objects, Object.freeze() also works on arrays:

const ingredients = ['beans', 'cheese', 'tortillas'];

Object.freeze(ingredients);

ingredients[0] = 'refried beans';

console.log(ingredients[0]);
// expected result: "beans";

It's again important to note that in all of these cases, a shallow freeze is being performed. If I had to do a deep freeze, I'd have to look into a solution that's probably a bit more advanced than what I could write myself. I'd probably start here. However, proceed with extreme caution trying to do any sort of deep freeze, as you might accidentally freeze something you're not supposed to (like the window object).

From MDN: The Object.freeze() method freezes an object. A frozen object can no longer be changed; freezing an object prevents new properties from being added to it, existing properties from being removed, prevents changing the enumerability, configurability, or writability of existing properties, and prevents the values of existing properties from being changed. In addition, freezing an object also prevents its prototype from being changed. freeze() returns the same object that was passed in.

See more examples and further documentation here.