madox2
madox2

Reputation: 51861

How to freeze nested objects in JavaScript?

I just stumbled upon Object.freeze() function. It seems to be a pretty good feature but how to make whole object (including nested objects) immutable?

For example I can change innerProp here:

const obj = { prop: { innerProp: 1 } };
obj.prop.innerProp = 5;
console.log(obj.prop.innerProp); // 5

Is it possible do freeze nested objects too? (ECMAScript 5/6)

Upvotes: 27

Views: 15741

Answers (5)

birdoftheday
birdoftheday

Reputation: 914

function deepFreeze (o) {
  Object.freeze(o);
  if (o === undefined) {
    return o;
  }
  
  Object.getOwnPropertyNames(o).forEach(function (prop) {
    if (o[prop] !== null
    && (typeof o[prop] === "object" || typeof o[prop] === "function")
    && !Object.isFrozen(o[prop])) {
      deepFreeze(o[prop]);
    }
  });
  
  return o;
};

https://www.npmjs.com/package/deep-freeze

It's public domain so you don't have to give credit :D

Upvotes: 30

Vidhi Kapadia
Vidhi Kapadia

Reputation: 11

One can freeze an object using recursive approach.

const deepFreeze = (param) => {
    Object.keys(param).forEach((val) => {
      if(typeof param[val] === "object"){
        deepFreeze(param[val]);
      }
    });
    return Object.freeze(param);
}

const obj = {
  name: "Vidhi",
  position: "Software Developer",
  travelling: {
    europe:"Rome",
    asia:"Tokyo",
  },
}

deepFreeze(obj);

obj.travelling.asia = "New York";  // cannot assign to read only property "asia" of obj
console.log(obj)

One can see in console that object's value has not changed and it will give error if we use strict mode in javascript.

Upvotes: -1

Sergey Sahakyan
Sergey Sahakyan

Reputation: 739

import { readonly } from 'vue/reactive'

let obj = { x: 1 }

obj = readonly(obj)

This will create a readonly proxy on the object and changes will have no effect. You can use the reference as a usual object.

You can use only reactive part of the vue 3, it's small import actually, but has lots of useful functionality

Upvotes: -3

rahul
rahul

Reputation: 2279

The function can be made much more terse in TS and ES2015.

import type { ReadonlyDeep } from 'type-fest';

export function deepFreeze<T>(o: T) {
  Object.values(o).forEach(v => Object.isFrozen(v) || deepFreeze(v));
  return Object.freeze(o) as ReadonlyDeep<T>;
}
  • Object.isFrozen now returns true for primitive objects.
  • Object.values instead of getOwnPropertyNames.

Upvotes: 5

user9550671
user9550671

Reputation: 19

const obj = { prop: { innerProp: 1 } };

Object.freeze(obj);
for(let key in obj) {
   if(obj.hasOwnProperty(key) && typeof obj[key] === 'object') {
      Object.freeze(obj[key]);
   }
}
obj.prop.innerProp = 5;
console.log(obj); // const obj = { prop: { innerProp: 1 } };

Upvotes: -1

Related Questions