deep-freeze-plus
Version:
An ultra-fast and efficient library for deeply freezing JavaScript objects and preventing unintended mutations. Supports all data types, including complex objects like maps and sets, and guarantees immutability without recursion. Ideal for applications th
61 lines (52 loc) • 1.81 kB
JavaScript
function deepFreeze(obj) {
const primitives = {
Boolean: true,
Number: true,
String: true,
Function: true
};
if (Object(obj) !== obj || primitives[obj.constructor.name]) {
return obj;
}
const seenObjects = new WeakSet();
const stack = [{obj, keys: Object.getOwnPropertyNames(obj)}];
const emptyKeys = [];
for (let i = 0; i < stack.length; i++) {
const {obj, keys} = stack[i];
if (!seenObjects.has(obj)) {
if (typeof obj !== 'object' || obj === null) {
// skip freezing primitive values
} else {
Object.freeze(obj);
seenObjects.add(obj);
}
}
for (let j = keys.length - 1; j >= 0; j--) {
const key = keys[j];
const value = obj[key];
if (value && typeof value === 'object' && !seenObjects.has(value)) {
let childKeys = emptyKeys;
if (!Object.isFrozen(value)) {
childKeys = Object.getOwnPropertyNames(value);
if (Array.isArray(value)) {
childKeys = childKeys.concat(Object.getOwnPropertyNames(Array.prototype));
}
}
if (value instanceof Map) {
for (const [mapKey, mapValue] of value) {
childKeys.push(mapKey);
stack.push({obj: mapValue, keys: Object.getOwnPropertyNames(mapValue)});
}
}
if (value instanceof Set) {
for (const setValue of value) {
stack.push({obj: setValue, keys: Object.getOwnPropertyNames(setValue)});
}
}
stack.push({obj: value, keys: childKeys});
}
}
}
return obj;
}
export default deepFreeze;