Difficulty: Intermediate
What are the key Object static methods? Explain property descriptors and immutability in JavaScript objects.
JavaScript provides several static methods on the Object constructor for working with objects. Object.keys() returns an array of own enumerable property names. Object.values() returns the values. Object.entries() returns key-value pairs as arrays. Object.assign() copies properties from source objects to a target.
Property descriptors control how individual properties behave. Each property has attributes: value, writable (can be changed), enumerable (shows in for...in), and configurable (can be deleted or reconfigured). Object.defineProperty() lets you set these attributes.
For immutability, Object.freeze() makes an object completely immutable (shallow), Object.seal() prevents adding/removing properties but allows modification, and Object.preventExtensions() only prevents adding new properties.
const user = { name: 'Alice', age: 25, role: 'developer' };
console.log(Object.keys(user)); // property names
console.log(Object.values(user)); // property values
console.log(Object.entries(user)); // [key, value] pairs
// Practical: transform object
const upperEntries = Object.entries(user)
.map(([key, val]) => [key, String(val).toUpperCase()]);
console.log(Object.fromEntries(upperEntries));
// Check if object has own property
console.log(Object.hasOwn(user, 'name')); // true
console.log(Object.hasOwn(user, 'toString')); // false
Object.entries and Object.fromEntries let you transform objects using array methods. Object.hasOwn replaces the older hasOwnProperty method.
const obj = {};
Object.defineProperty(obj, 'id', {
value: 42,
writable: false, // cannot change value
enumerable: true, // shows in Object.keys
configurable: false // cannot delete or reconfigure
});
console.log(obj.id); // 42
obj.id = 100; // silently fails (strict mode throws)
console.log(obj.id); // still 42
// Getter/setter descriptors
const person = { _age: 0 };
Object.defineProperty(person, 'age', {
get() { return this._age; },
set(val) {
if (val < 0) throw new Error('Age must be positive');
this._age = val;
},
enumerable: true
});
person.age = 25;
console.log(person.age);
console.log(Object.getOwnPropertyDescriptor(person, 'age'));
Property descriptors give fine-grained control over how properties behave. Getters/setters let you run logic on property access.
// Object.freeze - fully immutable (shallow)
const frozen = Object.freeze({ a: 1, b: { c: 2 } });
frozen.a = 10; // silently fails
frozen.d = 4; // silently fails
frozen.b.c = 99; // WORKS! freeze is shallow
console.log(frozen);
// Object.seal - can modify, cannot add/remove
const sealed = Object.seal({ x: 1, y: 2 });
sealed.x = 10; // works
sealed.z = 3; // silently fails
delete sealed.x; // silently fails
console.log(sealed);
// Deep freeze utility
function deepFreeze(obj) {
Object.freeze(obj);
Object.values(obj).forEach(val => {
if (typeof val === 'object' && val !== null) deepFreeze(val);
});
return obj;
}
const deep = deepFreeze({ a: { b: { c: 1 } } });
deep.a.b.c = 999;
console.log(deep.a.b.c); // still 1
freeze is shallow - nested objects are still mutable. You need a recursive deepFreeze to make the entire object tree immutable.
Object.keys, Object.entries, Property Descriptors, Object.freeze, Computed Properties, Object.assign