Objects
Literals, shorthand, computed keys, spread, destructuring, and JSON serialization quirks.
Objects are JavaScript's primary data structure: unordered key-value pairs where keys are strings (or symbols) and values can be anything.
Object literals support shorthand property names, computed keys, and method shorthand. These are purely syntactic - the runtime result is identical to the verbose form.
const name = "Ada";
const score = 98;
// Shorthand: { name: name, score: score }
const user = { name, score };
console.log(user); // { name: 'Ada', score: 98 }
// Computed key
const field = "role";
const record = { [field]: "admin" };
console.log(record); // { role: 'admin' }
// Method shorthand
const counter = {
count: 0,
increment() {
this.count++;
},
};
counter.increment();
console.log(counter.count); // 1Destructuring extracts named properties into local variables. Nested destructuring and defaults work too. The spread operator copies enumerable own properties into a new object.
const config = { host: "localhost", port: 5432, db: "main" };
// Destructure with rename and default
const { host, port: dbPort, ssl = false } = config;
console.log(host); // localhost
console.log(dbPort); // 5432
console.log(ssl); // false
// Spread: shallow copy with overrides
const devConfig = { ...config, port: 5433, db: "dev" };
console.log(devConfig);
// { host: 'localhost', port: 5433, db: 'dev' }
// Original untouched
console.log(config.port); // 5432JSON.stringify has three silent surprises: it drops undefined values and function properties, it throws on circular references, and Date objects become ISO strings (not re-parsed by JSON.parse).
const data = {
id: 1,
name: "Alice",
password: undefined, // dropped
greet() { return "hi"; }, // dropped
created: new Date("2024-01-01"),
};
const json = JSON.stringify(data);
console.log(json);
// {"id":1,"name":"Alice","created":"2024-01-01T00:00:00.000Z"}
// Circular reference throws
const a = {};
a.self = a;
try {
JSON.stringify(a);
} catch (e) {
console.log(e.message); // Converting circular structure to JSON
}
// JSON.parse does NOT restore Date objects - you get a string
const parsed = JSON.parse(json);
console.log(typeof parsed.created); // stringObject.freeze makes an object non-configurable and non-writable - but only one level deep. Nested objects are still mutable. structuredClone creates a true deep copy of most serializable values.
const settings = Object.freeze({ theme: "dark", limits: { max: 10 } });
settings.theme = "light"; // silently ignored (strict mode throws)
console.log(settings.theme); // dark - unchanged
settings.limits.max = 999; // nested object is NOT frozen
console.log(settings.limits.max); // 999
// Deep copy with structuredClone (Node 17+, modern browsers)
const original = { user: { name: "Bo", tags: ["a", "b"] } };
const copy = structuredClone(original);
copy.user.name = "Cal";
console.log(original.user.name); // Bo - truly independentIn production
The spread operator {...obj} copies only the top-level properties - nested objects are still shared by reference. Teams that treat spread as a deep clone and then mutate a nested field discover the bug when two callers observe each other's changes. For truly independent copies, use structuredClone (available in Node 17+ and modern browsers) or a library like Immer for immutable update patterns. TypeScript's Readonly<T> and as const give compile-time protection but do nothing at runtime - they catch the mistake in code review, not in production.
Enjoyed this? Get more essays on software craft delivered to your inbox.
Subscribe free