JavaScript provides powerful methods for working with objects. Here's a comprehensive guide.
Object.keys, values, entries#
1const user = {
2 name: 'Alice',
3 age: 30,
4 email: 'alice@example.com',
5};
6
7// Get keys
8const keys = Object.keys(user);
9console.log(keys); // ['name', 'age', 'email']
10
11// Get values
12const values = Object.values(user);
13console.log(values); // ['Alice', 30, 'alice@example.com']
14
15// Get entries (key-value pairs)
16const entries = Object.entries(user);
17console.log(entries);
18// [['name', 'Alice'], ['age', 30], ['email', 'alice@example.com']]
19
20// Iterate with entries
21for (const [key, value] of Object.entries(user)) {
22 console.log(`${key}: ${value}`);
23}
24
25// Transform object
26const upperKeys = Object.fromEntries(
27 Object.entries(user).map(([key, value]) => [key.toUpperCase(), value])
28);
29// { NAME: 'Alice', AGE: 30, EMAIL: 'alice@example.com' }Object.assign#
1// Shallow copy
2const original = { a: 1, b: 2 };
3const copy = Object.assign({}, original);
4
5// Merge objects
6const target = { a: 1, b: 2 };
7const source = { b: 3, c: 4 };
8const result = Object.assign(target, source);
9console.log(result); // { a: 1, b: 3, c: 4 }
10console.log(target === result); // true (mutates target)
11
12// Multiple sources
13const merged = Object.assign({}, obj1, obj2, obj3);
14
15// With defaults
16function configure(options) {
17 const defaults = {
18 debug: false,
19 timeout: 1000,
20 };
21 return Object.assign({}, defaults, options);
22}
23
24// Shallow copy caveat
25const nested = {
26 a: 1,
27 b: { c: 2 },
28};
29const shallowCopy = Object.assign({}, nested);
30shallowCopy.b.c = 100;
31console.log(nested.b.c); // 100 (same reference!)Object.fromEntries#
1// Convert entries to object
2const entries = [
3 ['name', 'Alice'],
4 ['age', 30],
5];
6const obj = Object.fromEntries(entries);
7// { name: 'Alice', age: 30 }
8
9// From Map
10const map = new Map([
11 ['foo', 'bar'],
12 ['baz', 42],
13]);
14const objFromMap = Object.fromEntries(map);
15// { foo: 'bar', baz: 42 }
16
17// Transform object values
18const prices = {
19 apple: 1.5,
20 banana: 0.75,
21 orange: 2.0,
22};
23
24const discounted = Object.fromEntries(
25 Object.entries(prices).map(([item, price]) => [item, price * 0.9])
26);
27// { apple: 1.35, banana: 0.675, orange: 1.8 }
28
29// Filter object
30const user = {
31 name: 'Alice',
32 age: 30,
33 password: 'secret',
34 email: 'alice@example.com',
35};
36
37const safe = Object.fromEntries(
38 Object.entries(user).filter(([key]) => key !== 'password')
39);
40// { name: 'Alice', age: 30, email: 'alice@example.com' }Property Descriptors#
1// Get descriptor
2const obj = { name: 'Alice' };
3const descriptor = Object.getOwnPropertyDescriptor(obj, 'name');
4console.log(descriptor);
5// {
6// value: 'Alice',
7// writable: true,
8// enumerable: true,
9// configurable: true
10// }
11
12// Define property with descriptor
13Object.defineProperty(obj, 'id', {
14 value: 1,
15 writable: false,
16 enumerable: true,
17 configurable: false,
18});
19
20obj.id = 2; // Fails silently (or throws in strict mode)
21console.log(obj.id); // 1
22
23// Define multiple properties
24Object.defineProperties(obj, {
25 firstName: {
26 value: 'Alice',
27 writable: true,
28 },
29 lastName: {
30 value: 'Smith',
31 writable: true,
32 },
33});
34
35// Getter and setter
36Object.defineProperty(obj, 'fullName', {
37 get() {
38 return `${this.firstName} ${this.lastName}`;
39 },
40 set(value) {
41 const [first, last] = value.split(' ');
42 this.firstName = first;
43 this.lastName = last;
44 },
45 enumerable: true,
46});
47
48console.log(obj.fullName); // 'Alice Smith'
49obj.fullName = 'Bob Jones';
50console.log(obj.firstName); // 'Bob'Object.freeze, seal, preventExtensions#
1// Freeze - no changes at all
2const frozen = Object.freeze({
3 name: 'Alice',
4 address: { city: 'NYC' },
5});
6
7frozen.name = 'Bob'; // Fails silently
8frozen.age = 30; // Fails silently
9delete frozen.name; // Fails silently
10frozen.address.city = 'LA'; // Works! (shallow freeze)
11
12console.log(Object.isFrozen(frozen)); // true
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, but not add/delete
25const sealed = Object.seal({
26 name: 'Alice',
27 age: 30,
28});
29
30sealed.name = 'Bob'; // Works
31sealed.email = 'x'; // Fails silently
32delete sealed.age; // Fails silently
33
34console.log(Object.isSealed(sealed)); // true
35
36// Prevent extensions - can modify/delete, but not add
37const obj = { name: 'Alice' };
38Object.preventExtensions(obj);
39
40obj.name = 'Bob'; // Works
41delete obj.name; // Works
42obj.age = 30; // Fails silently
43
44console.log(Object.isExtensible(obj)); // falseObject.create#
1// Create with prototype
2const animal = {
3 speak() {
4 console.log(`${this.name} makes a sound`);
5 },
6};
7
8const dog = Object.create(animal);
9dog.name = 'Buddy';
10dog.speak(); // 'Buddy makes a sound'
11
12// Create with property descriptors
13const person = Object.create(Object.prototype, {
14 name: {
15 value: 'Alice',
16 writable: true,
17 enumerable: true,
18 },
19 greet: {
20 value: function () {
21 return `Hello, I'm ${this.name}`;
22 },
23 enumerable: true,
24 },
25});
26
27// Create with null prototype (no inherited methods)
28const dict = Object.create(null);
29dict.foo = 'bar';
30console.log(dict.toString); // undefined (no inherited methods)
31
32// Useful for lookup maps
33const lookup = Object.create(null);
34lookup['hasOwnProperty'] = 'safe'; // No collision with Object.prototypeObject.getPrototypeOf, setPrototypeOf#
1// Get prototype
2const arr = [];
3console.log(Object.getPrototypeOf(arr) === Array.prototype); // true
4
5class Animal {}
6class Dog extends Animal {}
7const dog = new Dog();
8
9console.log(Object.getPrototypeOf(dog) === Dog.prototype); // true
10console.log(Object.getPrototypeOf(Dog.prototype) === Animal.prototype); // true
11
12// Set prototype (not recommended for performance)
13const obj = { a: 1 };
14const proto = { b: 2 };
15Object.setPrototypeOf(obj, proto);
16
17console.log(obj.b); // 2
18
19// Check prototype chain
20console.log(proto.isPrototypeOf(obj)); // trueObject.is#
1// Strict equality with special cases
2console.log(Object.is(1, 1)); // true
3console.log(Object.is('a', 'a')); // true
4console.log(Object.is({}, {})); // false (different references)
5
6// Different from ===
7console.log(NaN === NaN); // false
8console.log(Object.is(NaN, NaN)); // true
9
10console.log(-0 === 0); // true
11console.log(Object.is(-0, 0)); // false
12
13// Use cases
14function sameValue(a, b) {
15 return Object.is(a, b);
16}
17
18// In React, used for shallow comparison
19function shallowEqual(obj1, obj2) {
20 const keys1 = Object.keys(obj1);
21 const keys2 = Object.keys(obj2);
22
23 if (keys1.length !== keys2.length) return false;
24
25 for (const key of keys1) {
26 if (!Object.is(obj1[key], obj2[key])) return false;
27 }
28
29 return true;
30}Object.hasOwn#
1// Modern way to check own properties
2const obj = { name: 'Alice' };
3
4console.log(Object.hasOwn(obj, 'name')); // true
5console.log(Object.hasOwn(obj, 'toString')); // false (inherited)
6
7// Better than hasOwnProperty
8const dict = Object.create(null);
9dict.key = 'value';
10
11// This would throw
12// dict.hasOwnProperty('key')
13
14// This works
15Object.hasOwn(dict, 'key'); // true
16
17// Also works with overridden hasOwnProperty
18const tricky = {
19 hasOwnProperty: () => false,
20 name: 'Alice',
21};
22
23console.log(tricky.hasOwnProperty('name')); // false (wrong!)
24console.log(Object.hasOwn(tricky, 'name')); // true (correct)Object.getOwnPropertyNames/Symbols#
1const sym = Symbol('hidden');
2
3const obj = {
4 name: 'Alice',
5 age: 30,
6 [sym]: 'secret',
7};
8
9// Get all string-keyed properties (including non-enumerable)
10console.log(Object.getOwnPropertyNames(obj));
11// ['name', 'age']
12
13// Get all symbol-keyed properties
14console.log(Object.getOwnPropertySymbols(obj));
15// [Symbol(hidden)]
16
17// Get all properties
18const allKeys = [
19 ...Object.getOwnPropertyNames(obj),
20 ...Object.getOwnPropertySymbols(obj),
21];
22// ['name', 'age', Symbol(hidden)]
23
24// Or use Reflect.ownKeys
25console.log(Reflect.ownKeys(obj));
26// ['name', 'age', Symbol(hidden)]
27
28// Get all descriptors
29const descriptors = Object.getOwnPropertyDescriptors(obj);Practical Patterns#
1// Pick specific properties
2function pick(obj, keys) {
3 return Object.fromEntries(
4 keys.filter(key => key in obj).map(key => [key, obj[key]])
5 );
6}
7
8const user = { name: 'Alice', age: 30, email: 'a@b.com', password: 'x' };
9const safe = pick(user, ['name', 'age', 'email']);
10
11// Omit specific properties
12function omit(obj, keys) {
13 return Object.fromEntries(
14 Object.entries(obj).filter(([key]) => !keys.includes(key))
15 );
16}
17
18const withoutPassword = omit(user, ['password']);
19
20// Map object values
21function mapValues(obj, fn) {
22 return Object.fromEntries(
23 Object.entries(obj).map(([key, value]) => [key, fn(value, key)])
24 );
25}
26
27const doubled = mapValues({ a: 1, b: 2 }, x => x * 2);
28// { a: 2, b: 4 }
29
30// Group by property
31function groupBy(arr, key) {
32 return arr.reduce((acc, item) => {
33 const group = item[key];
34 acc[group] = acc[group] || [];
35 acc[group].push(item);
36 return acc;
37 }, {});
38}
39
40const users = [
41 { name: 'Alice', role: 'admin' },
42 { name: 'Bob', role: 'user' },
43 { name: 'Charlie', role: 'admin' },
44];
45
46const byRole = groupBy(users, 'role');
47// { admin: [...], user: [...] }Best Practices#
Immutability:
✓ Use Object.assign({}, obj) or spread
✓ Use Object.freeze for constants
✓ Deep clone when needed
✓ Consider immutable libraries
Property Access:
✓ Use Object.hasOwn over hasOwnProperty
✓ Use optional chaining for nested access
✓ Check for null/undefined
✓ Use default values
Iteration:
✓ Use Object.entries for key-value
✓ Use Object.keys for keys only
✓ Consider for...in with hasOwn
✓ Use Object.fromEntries to reconstruct
Performance:
✓ Avoid Object.setPrototypeOf
✓ Cache Object.keys results
✓ Use Map for frequent additions
✓ Consider frozen objects for constants
Conclusion#
JavaScript's object methods provide powerful tools for manipulation, iteration, and protection. Use Object.entries/fromEntries for transformations, property descriptors for fine-grained control, and Object.freeze/seal for immutability. Modern methods like Object.hasOwn offer safer alternatives to older patterns.