javascript
30 lines · 6 steps
Recursively freezing a nested object
A small recursive helper walks every property and freezes each object so a whole config tree becomes deeply immutable.
Explained by
highlit
1function deepFreeze(obj) {
2 const propNames = Reflect.ownKeys(obj);
3
4 for (const name of propNames) {
5 const value = obj[name];
6 if ((value && typeof value === 'object') || typeof value === 'function') {
7 deepFreeze(value);
8 }
9 }
10
11 return Object.freeze(obj);
12}
13
14const config = deepFreeze({
15 env: 'production',
16 server: {
17 host: '0.0.0.0',
18 port: 8080,
19 tls: {
20 enabled: true,
21 ciphers: ['TLS_AES_256_GCM_SHA384'],
22 },
23 },
24 featureFlags: {
25 betaSearch: false,
26 darkMode: true,
27 },
28});
29
30export default config;
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Object.freeze is shallow, so nested objects need recursion to become truly immutable.
- 2Reflect.ownKeys captures string and symbol keys, including non-enumerable ones, unlike a plain for...in.
- 3Freezing children before the parent guarantees the entire tree is locked by the time the top-level call returns.
Related explainers
javascript
function evaluate(expression) { const tokens = tokenize(expression); let pos = 0;
Building a recursive descent calculator
parsing
recursion
operator-precedence
Intermediate
8 steps
javascript
import { useState, useEffect, useCallback, useRef } from 'react'; const cache = new Map(); const inflight = new Map();
Building a stale-while-revalidate hook in React
caching
request-deduplication
custom-hooks
Advanced
10 steps
go
package logging import ( "context"
Deduplicating log attributes in Go's slog
decorator-pattern
structured-logging
immutability
Intermediate
8 steps
javascript
import { useEffect, useRef, useState } from 'react'; export function useDelayedFlag(active, delay = 300) { const [visible, setVisible] = useState(false);
Delaying a loading spinner with a React hook
custom-hooks
debouncing
cleanup
Intermediate
8 steps
javascript
const SWIPE_THRESHOLD = 80; const MAX_TRANSLATE = 120; export function attachSwipeToDismiss(element, onDismiss) {
Building a swipe-to-dismiss gesture in JS
touch-events
gesture-detection
dom-manipulation
Intermediate
10 steps
javascript
const { pool } = require('./db'); function withTransaction() { return async (req, res, next) => {
A per-request transaction middleware in Express
middleware
database-transactions
connection-pooling
Advanced
7 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/recursively-freezing-a-nested-object-explained-javascript-b031/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.