JavaScript provides powerful Object methods for working with objects. Here's a comprehensive guide.
Object.keys(), values(), entries()#
1const user = {
2 name: 'John',
3 age: 30,
4 email: 'john@example.com'
5};
6
7// Get keys
8const keys = Object.keys(user);
9// ['name', 'age', 'email']
10
11// Get values
12const values = Object.values(user);
13// ['John', 30, 'john@example.com']
14
15// Get entries (key-value pairs)
16const entries = Object.entries(user);
17// [['name', 'John'], ['age', 30], ['email', 'john@example.com']]
18
19// Iterate over object
20for (const [key, value] of Object.entries(user)) {
21 console.log(`${key}: ${value}`);
22}
23
24// Transform object
25const doubled = Object.fromEntries(
26 Object.entries(user).map(([key, value]) => [
27 key,
28 typeof value === 'number' ? value * 2 : value
29 ])
30);Object.assign()#
1// Merge objects
2const defaults = { theme: 'light', lang: 'en' };
3const userPrefs = { theme: 'dark' };
4
5const config = Object.assign({}, defaults, userPrefs);
6// { theme: 'dark', lang: 'en' }
7
8// Clone object (shallow)
9const original = { a: 1, b: { c: 2 } };
10const clone = Object.assign({}, original);
11
12// Note: nested objects are still referenced
13clone.b.c = 3;
14console.log(original.b.c); // 3
15
16// Multiple sources
17const merged = Object.assign(
18 {},
19 { a: 1 },
20 { b: 2 },
21 { a: 3, c: 4 }
22);
23// { a: 3, b: 2, c: 4 } - later values override
24
25// Mutate target
26const target = { a: 1 };
27Object.assign(target, { b: 2 });
28// target is now { a: 1, b: 2 }Object.fromEntries()#
1// Convert entries to object
2const entries = [
3 ['name', 'John'],
4 ['age', 30]
5];
6
7const obj = Object.fromEntries(entries);
8// { name: 'John', age: 30 }
9
10// From Map
11const map = new Map([
12 ['a', 1],
13 ['b', 2]
14]);
15
16const fromMap = Object.fromEntries(map);
17// { a: 1, b: 2 }
18
19// Transform object
20const original = { a: 1, b: 2, c: 3 };
21
22const transformed = Object.fromEntries(
23 Object.entries(original)
24 .filter(([key]) => key !== 'b')
25 .map(([key, value]) => [key.toUpperCase(), value * 10])
26);
27// { A: 10, C: 30 }
28
29// Query string to object
30const queryString = 'name=John&age=30&city=NYC';
31const params = Object.fromEntries(
32 new URLSearchParams(queryString)
33);
34// { name: 'John', age: '30', city: 'NYC' }Object.freeze() and Object.seal()#
1// Freeze - no changes allowed
2const frozen = Object.freeze({
3 name: 'John',
4 details: { age: 30 }
5});
6
7frozen.name = 'Jane'; // Silently fails (or throws in strict mode)
8frozen.email = 'test'; // Silently fails
9delete frozen.name; // Silently fails
10
11// Note: Nested objects are NOT frozen
12frozen.details.age = 31; // Works!
13
14// Deep freeze
15function deepFreeze(obj) {
16 Object.keys(obj).forEach(key => {
17 if (typeof obj[key] === 'object' && obj[key] !== null) {
18 deepFreeze(obj[key]);
19 }
20 });
21 return Object.freeze(obj);
22}
23
24// Seal - can modify existing, can't add/remove
25const sealed = Object.seal({ name: 'John', age: 30 });
26
27sealed.name = 'Jane'; // Works
28sealed.email = 'test'; // Fails
29delete sealed.name; // Fails
30
31// Check status
32Object.isFrozen(frozen); // true
33Object.isSealed(sealed); // trueObject.defineProperty()#
1const obj = {};
2
3// Define property with descriptors
4Object.defineProperty(obj, 'name', {
5 value: 'John',
6 writable: true, // Can be changed
7 enumerable: true, // Shows in for...in
8 configurable: true // Can be deleted/modified
9});
10
11// Read-only property
12Object.defineProperty(obj, 'id', {
13 value: 123,
14 writable: false,
15 enumerable: true,
16 configurable: false
17});
18
19obj.id = 456; // Fails silently (or throws in strict)
20
21// Getter and setter
22Object.defineProperty(obj, 'fullName', {
23 get() {
24 return `${this.firstName} ${this.lastName}`;
25 },
26 set(value) {
27 const [first, last] = value.split(' ');
28 this.firstName = first;
29 this.lastName = last;
30 },
31 enumerable: true
32});
33
34// Define multiple properties
35Object.defineProperties(obj, {
36 firstName: { value: 'John', writable: true, enumerable: true },
37 lastName: { value: 'Doe', writable: true, enumerable: true }
38});Object.getOwnPropertyDescriptor()#
1const obj = {
2 name: 'John',
3 get fullName() {
4 return this.name;
5 }
6};
7
8// Get single descriptor
9const desc = Object.getOwnPropertyDescriptor(obj, 'name');
10// { value: 'John', writable: true, enumerable: true, configurable: true }
11
12// Get getter descriptor
13const getterDesc = Object.getOwnPropertyDescriptor(obj, 'fullName');
14// { get: [Function], set: undefined, enumerable: true, configurable: true }
15
16// Get all descriptors
17const allDesc = Object.getOwnPropertyDescriptors(obj);
18
19// Clone with descriptors preserved
20const clone = Object.defineProperties(
21 {},
22 Object.getOwnPropertyDescriptors(obj)
23);Object.create()#
1// Create with prototype
2const personProto = {
3 greet() {
4 return `Hello, ${this.name}`;
5 }
6};
7
8const person = Object.create(personProto);
9person.name = 'John';
10person.greet(); // 'Hello, John'
11
12// With property descriptors
13const user = Object.create(personProto, {
14 name: {
15 value: 'John',
16 writable: true,
17 enumerable: true
18 },
19 age: {
20 value: 30,
21 writable: false
22 }
23});
24
25// Create null prototype object
26const dict = Object.create(null);
27dict.hasOwnProperty; // undefined - no inherited methods
28dict['key'] = 'value';
29
30// Useful for dictionary-like objects
31function createDict() {
32 return Object.create(null);
33}Object.getPrototypeOf() and setPrototypeOf()#
1const animal = {
2 speak() {
3 console.log('Animal speaks');
4 }
5};
6
7const dog = {
8 bark() {
9 console.log('Woof!');
10 }
11};
12
13// Get prototype
14const proto = Object.getPrototypeOf(dog);
15// Object.prototype
16
17// Set prototype (not recommended for performance)
18Object.setPrototypeOf(dog, animal);
19
20dog.speak(); // 'Animal speaks'
21dog.bark(); // 'Woof!'
22
23// Check prototype chain
24Object.getPrototypeOf(dog) === animal; // trueObject.is()#
1// Stricter equality than ===
2Object.is(25, 25); // true
3Object.is('foo', 'foo'); // true
4Object.is(null, null); // true
5
6// Handles special cases differently than ===
7Object.is(NaN, NaN); // true (=== returns false)
8Object.is(0, -0); // false (=== returns true)
9
10// Same as === for most cases
11Object.is([], []); // false (different references)
12
13// Useful for comparing values
14function equals(a, b) {
15 return Object.is(a, b);
16}Object.hasOwn()#
1// Modern replacement for hasOwnProperty
2const obj = { name: 'John' };
3
4Object.hasOwn(obj, 'name'); // true
5Object.hasOwn(obj, 'toString'); // false (inherited)
6
7// Works with null prototype objects
8const dict = Object.create(null);
9dict.key = 'value';
10
11// Old way fails on null prototype
12// dict.hasOwnProperty('key'); // Error!
13
14// New way works
15Object.hasOwn(dict, 'key'); // true
16
17// Safer than in operator
18'name' in obj; // true
19'toString' in obj; // true (checks prototype chain)
20Object.hasOwn(obj, 'toString'); // falseObject.groupBy() (ES2024)#
1const items = [
2 { name: 'Apple', type: 'fruit' },
3 { name: 'Carrot', type: 'vegetable' },
4 { name: 'Banana', type: 'fruit' },
5 { name: 'Broccoli', type: 'vegetable' }
6];
7
8// Group by property
9const grouped = Object.groupBy(items, item => item.type);
10// {
11// fruit: [{ name: 'Apple', ... }, { name: 'Banana', ... }],
12// vegetable: [{ name: 'Carrot', ... }, { name: 'Broccoli', ... }]
13// }
14
15// Group numbers
16const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];
17const byParity = Object.groupBy(numbers, n =>
18 n % 2 === 0 ? 'even' : 'odd'
19);
20// { odd: [1, 3, 5, 7, 9], even: [2, 4, 6, 8] }Iteration Patterns#
1const obj = { a: 1, b: 2, c: 3 };
2
3// for...in (includes inherited, use hasOwn to filter)
4for (const key in obj) {
5 if (Object.hasOwn(obj, key)) {
6 console.log(key, obj[key]);
7 }
8}
9
10// Object.keys + forEach
11Object.keys(obj).forEach(key => {
12 console.log(key, obj[key]);
13});
14
15// Object.entries + destructuring
16for (const [key, value] of Object.entries(obj)) {
17 console.log(key, value);
18}
19
20// Reduce to transform
21const doubled = Object.entries(obj).reduce(
22 (acc, [key, value]) => ({ ...acc, [key]: value * 2 }),
23 {}
24);Best Practices#
Common Methods:
✓ Object.keys/values/entries for iteration
✓ Object.assign for merging
✓ Object.fromEntries for transformation
✓ Object.hasOwn for property checks
Immutability:
✓ Object.freeze for constants
✓ Spread for shallow copies
✓ Deep clone for nested objects
✓ Consider libraries for complex cases
Descriptors:
✓ defineProperty for advanced control
✓ getOwnPropertyDescriptors for cloning
✓ Use for computed properties
✓ Understand enumerable/configurable
Avoid:
✗ Mutating frozen objects
✗ setPrototypeOf in hot paths
✗ hasOwnProperty on null prototype
✗ Confusing === with Object.is
Conclusion#
JavaScript Object methods provide powerful tools for manipulating objects. Use Object.keys/values/entries for iteration, Object.assign or spread for merging, and Object.fromEntries for transformation. For advanced use cases, Object.defineProperty and descriptors offer fine-grained control. Always consider whether you need shallow or deep operations.