Why const isn't  always constant in JavaScript

Why const isn't always constant in JavaScript


Table of Contents:

  1. Introduction

  2. Why const isn't always constant in JavaScript and TypeScript

  3. How this relates to state managers

  4. How this impacts React

  5. How to make an object immutable

  6. Conclusion

Introduction

When we declare a variable with the const keyword in JavaScript and TypeScript, we expect it to be immutable, meaning that its value cannot be changed. This is generally true for simple values like numbers, booleans, and strings. However, when it comes to objects and arrays, things get a little more complicated.

Why const isn't always constant in JavaScript and TypeScript

In JavaScript and TypeScript, objects and arrays are stored by reference, not by value. This means that when you declare a constant object or array, you are actually declaring a constant reference to that object or array. This means that you cannot reassign the variable to a different object or array, but you can still mutate the object or array itself.

const person = { name: "Mohamed" };

// This will throw an error:
// Assignment to constant variable.
person = { name: "John" };

// This is perfectly fine:
person.name = "John";

In the first example, we are trying to reassign the person variable to a different object. This will throw an error because person is a constant variable.

In the second example, we are mutating the person object by changing the value of the name property. This is perfectly fine because we are not reassigning the person variable itself.

diagram example:

How this relates to state managers:

When we use a state manager like Redux or MobX, we are typically storing our state as objects. This means that the same principles that apply to constant object values also apply to constant state values.

For example, if we have a constant state value called person, we can still mutate the person object by changing the value of the name property. However, if we try to reassign the person state value to a different object, our state manager will not update the state.

How this impacts React:

When we use the useState hook in React, we are returning a constant object value. This means that the same principles that apply to constant object values also apply to constant state values in React.

For example, if we have a constant state value called person, we can still mutate the person object by changing the value of the name property. However, if we try to reassign the person state value to a different object, our React component will not re-render.

How to make an object immutable

If you want to make an object immutable, you can use the Object.freeze() method. This will prevent any changes to the object's properties, including nested objects.

Here is an example:

let someObj = {};
someObj.prop = 1; // setting prop to '1'

Object.freeze(someObj); // after this line you can't modify object
someObj.prop = "changed"; // prop will remain '1'
console.log(someObj); // { prop: 1 }

Note: Object.freeze() is a shallow freeze, meaning that nested objects can still be modified. To make nested objects immutable, you can use recursion.

Here is an example of a recursive function to freeze an object completely:

function completeFreeze(obj) {
  Object.freeze(obj);
  for (let key in obj) {
    if (typeof obj[key] === "object") {
      completeFreeze(obj[key]);
    }
  }
}

To use this function, simply pass the object that you want to freeze to it. For example:

const obj = {
  upper: "something",
  nested: {
    nestProp: "this is nest prop",
  },
};

completeFreeze(obj);

obj.nested.upper = "new"; // will not be changed

console.log(obj); // { upper: 'something', nested: { nestProp: 'this is nest prop' } }

Conclusion:

In conclusion, it is important to be aware that const is not always constant in JavaScript and TypeScript. When it comes to objects and arrays, const only prevents you from reassigning the variable to a different object or array. You can still mutate the object or array itself.

When using state managers and React, it is important to keep this in mind because it can impact how your state is updated and your components are re-rendered.

Additionally, you can use the Object.freeze() method to make an object immutable. This will prevent any changes to the object's properties, including nested objects. You can also use a recursive function to freeze an object completely.

I hope this blog article has been helpful in explaining why const isn't always constant in JavaScript and TypeScript, and how to avoid the common pitfalls.

Let's connect: