|

JavaScript 46 🧬 Object methods in depth

const obj = { a: 1, b: 2, c: 3 };

Object.keys(obj);
Object.values(obj);
Object.entries(obj);
Object.fromEntries([['a', 1], ['b', 2]]);
Object.assign({}, obj, { d: 4 });
Object.freeze(obj);
Object.seal(obj);
Object.isFrozen(obj);
Object.isSealed(obj);
Object.hasOwn(obj, 'a');
Object.create(null);
Object.defineProperty(obj, 'x', { value: 42 });
Object.getOwnPropertyDescriptor(obj, 'a');
Object.getPrototypeOf(obj);
Object.setPrototypeOf(obj, null);
Object.is(1, 1);
Object.is(NaN, NaN);
Object.groupBy([1, 2, 3, 4], n => n % 2 === 0 ? 'even' : 'odd');

The Object global is a toolbox — it’s the constructor for objects, but it also holds static methods that work on any object. These methods are how you enumerate, copy, freeze, compare, and inspect objects. They’re the foundation of modern JavaScript patterns like immutability and destructuring.

Key point: Most Object.* methods work on own enumerable properties by default. Some methods work on prototypes, symbols, or descriptors. Knowing which is which prevents surprises when objects have inherited properties.


a – Enumerating object properties

These methods give you arrays of keys, values, or key-value pairs.

Object.keys() — array of keys:

const user = { name: 'Alice', age: 30 };

console.log(Object.keys(user));
// [ [ 'name', 'age' ] ]

Only own enumerable properties, in insertion order.

Object.values() — array of values:

console.log(Object.values(user));
// [ [ 'Alice', 30 ] ]

Object.entries() — array of [key, value] pairs:

console.log(Object.entries(user));
// [ [ [ 'name', 'Alice' ], [ 'age', 30 ] ] ]

Object.fromEntries() — the reverse:

const entries = [['name', 'Alice'], ['age', 30]];
const user = Object.fromEntries(entries);

console.log(user);
// [ { name: 'Alice', age: 30 } ]

Converting Map to Object:

const map = new Map([['a', 1], ['b', 2]]);
const obj = Object.fromEntries(map);

console.log(obj);
// [ { a: 1, b: 2 } ]

Converting Object to Map:

const obj = { a: 1, b: 2 };
const map = new Map(Object.entries(obj));

console.log(map);
// [ Map(2) { 'a' => 1, 'b' => 2 } ]

Iterating with Object.entries():

const prices = { apple: 1.5, banana: 0.75 };

for (const [fruit, price] of Object.entries(prices)) {
  console.log(`${fruit}: $${price}`);
}
// [ apple: $1.5 ]
// [ banana: $0.75 ]

Transforming values:

const prices = { apple: 1.5, banana: 0.75 };

const doubled = Object.fromEntries(
  Object.entries(prices).map(([k, v]) => [k, v * 2])
);

console.log(doubled);
// [ { apple: 3, banana: 1.5 } ]

Filtering:

const mixed = { a: 1, b: null, c: 3, d: undefined };

const clean = Object.fromEntries(
  Object.entries(mixed).filter(([_, v]) => v != null)
);

console.log(clean);
// [ { a: 1, c: 3 } ]

Comparison:

MethodReturns
Object.keys(obj)Array of keys
Object.values(obj)Array of values
Object.entries(obj)Array of [key, value]
Object.fromEntries(arr)Object from pairs

Property order:

Key typeOrder
Integer-likeNumeric ascending
StringInsertion order
SymbolInsertion order
const obj = { b: 1, 2: 'two', a: 3, 1: 'one' };
console.log(Object.keys(obj));
// [ [ '1', '2', 'b', 'a' ] ]

b – Copying, merging, and comparing

Object.assign() — copy and merge:

const target = { a: 1 };
const source = { b: 2, c: 3 };

Object.assign(target, source);
console.log(target);
// [ { a: 1, b: 2, c: 3 } ]

The target is mutated. To create a new object, use an empty target:

const merged = Object.assign({}, { a: 1 }, { b: 2 });
console.log(merged);
// [ { a: 1, b: 2 } ]

Later sources override earlier ones:

Object.assign({}, { a: 1, b: 2 }, { b: 3 });
// [ { a: 1, b: 3 } ]

Object.assign is shallow:

const original = { a: { x: 1 } };
const copy = Object.assign({}, original);

copy.a.x = 99;
console.log(original.a.x);
// [ 99 ]  ← shared

Spread vs Object.assign:

// These are equivalent
const merged1 = Object.assign({}, a, b);
const merged2 = { ...a, ...b };

Spread is preferred in modern code.

Object.is() — strict equality with edge cases:

console.log(Object.is(1, 1));
// [ true ]

console.log(Object.is('a', 'a'));
// [ true ]

console.log(Object.is({}, {}));
// [ false ]

Object.is differs from === in two cases:

console.log(NaN === NaN);
// [ false ]

console.log(Object.is(NaN, NaN));
// [ true ]

console.log(+0 === -0);
// [ true ]

console.log(Object.is(+0, -0));
// [ false ]
Case===Object.is
NaN === NaNfalsetrue
+0 === -0truefalse
Normal valuesSameSame

Use Object.is when you need exact identity, especially with NaN or signed zeros.

Shallow vs deep copy:

// Shallow — spread or assign
const shallow = { ...original };

// Deep — structuredClone
const deep = structuredClone(original);

structuredClone handles nested objects, arrays, Maps, Sets, Dates — but not functions or class instances.

Comparing objects:

const a = { x: 1 };
const b = { x: 1 };

console.log(a === b);
// [ false ]  ← different references

console.log(JSON.stringify(a) === JSON.stringify(b));
// [ true ]  ← same shape and values

console.log(Object.is(a, b));
// [ false ]

Objects compare by reference, not by structure.


c – Freezing and sealing

These methods control whether an object can be modified.

Object.freeze() — fully immutable:

const config = Object.freeze({ host: 'localhost', port: 8080 });

config.port = 9090;
console.log(config.port);
// [ 8080 ]  ← unchanged

config.newKey = 'x';
console.log(config.newKey);
// [ undefined ]

delete config.host;
console.log(config.host);
// [ 'localhost' ]  ← still there

You can’t add, modify, or delete properties on a frozen object. In strict mode, these operations throw:

'use strict';
const obj = Object.freeze({ a: 1 });
obj.a = 2;   // TypeError: Cannot assign to read only property

Object.seal() — no add/delete, but modify allowed:

const user = Object.seal({ name: 'Alice', age: 30 });

user.age = 31;         // ✅ works
user.newKey = 'x';     // ❌ ignored
delete user.name;      // ❌ ignored

Existing properties can be changed; new ones can’t be added or removed.

Object.preventExtensions() — no new properties:

const obj = Object.preventExtensions({ a: 1 });

obj.a = 2;             // ✅ works
obj.b = 3;             // ❌ ignored
delete obj.a;          // ✅ works

Comparison:

MethodAddModifyDelete
Object.freeze
Object.seal
Object.preventExtensions
(default)

Checking:

const frozen = Object.freeze({ a: 1 });
const sealed = Object.seal({ a: 1 });
const prevented = Object.preventExtensions({ a: 1 });

console.log(Object.isFrozen(frozen));
// [ true ]

console.log(Object.isSealed(sealed));
// [ true ]

console.log(Object.isExtensible(prevented));
// [ false ]

Freeze is shallow:

const obj = Object.freeze({ a: { b: 1 } });
obj.a.b = 99;   // ✅ still works — inner object not frozen

console.log(obj.a.b);
// [ 99 ]

To freeze deeply, recurse:

function deepFreeze(obj) {
  Object.freeze(obj);
  Object.values(obj).forEach(v => {
    if (v && typeof v === 'object') deepFreeze(v);
  });
  return obj;
}

d – Property descriptors and creation

Object.defineProperty() — precise property control:

const obj = {};

Object.defineProperty(obj, 'x', {
  value: 42,
  writable: false,
  enumerable: false,
  configurable: false
});

console.log(obj.x);
// [ 42 ]

obj.x = 99;
console.log(obj.x);
// [ 42 ]  ← unchanged (writable: false)

Descriptor flags:

FlagMeaning
valueThe value
writableCan be changed
enumerableShows in for...in, Object.keys
configurableCan be deleted or redefined
getGetter function
setSetter function

Object.defineProperties() — multiple properties:

const obj = {};

Object.defineProperties(obj, {
  name: { value: 'Alice', enumerable: true },
  age: { value: 30, enumerable: true }
});

console.log(obj);
// [ { name: 'Alice', age: 30 } ]

Object.getOwnPropertyDescriptor() — inspect a descriptor:

const obj = { a: 1 };
const desc = Object.getOwnPropertyDescriptor(obj, 'a');

console.log(desc);
// [ { value: 1, writable: true, enumerable: true, configurable: true } ]

Object.getOwnPropertyDescriptors() — all descriptors:

const obj = { a: 1, b: 2 };
console.log(Object.getOwnPropertyDescriptors(obj));
// [ { a: {...}, b: {...} } ]

Getters and setters with defineProperty:

const obj = {
  _value: 0
};

Object.defineProperty(obj, 'value', {
  get() { return this._value; },
  set(v) { this._value = v * 2; }
});

obj.value = 10;
console.log(obj.value);
// [ 20 ]

Object.create() — create with a prototype:

const proto = {
  greet() { return `Hello, ${this.name}`; }
};

const obj = Object.create(proto);
obj.name = 'Alice';

console.log(obj.greet());
// [ Hello, Alice ]

console.log(Object.getPrototypeOf(obj) === proto);
// [ true ]

Object.create(null) — object with no prototype:

const dict = Object.create(null);
dict.key = 'value';

console.log(dict.key);
// [ 'value' ]

console.log(dict.toString);
// [ undefined ]  ← no inherited methods

This is useful for pure key-value storage without prototype pollution.

Object.getPrototypeOf and Object.setPrototypeOf:

const proto = { a: 1 };
const obj = { b: 2 };

Object.setPrototypeOf(obj, proto);
console.log(Object.getPrototypeOf(obj) === proto);
// [ true ]

Object.setPrototypeOf is slow — avoid it in hot paths.

Object.hasOwn — own property check (ES2022):

const obj = { a: 1 };

console.log(Object.hasOwn(obj, 'a'));
// [ true ]

console.log(Object.hasOwn(obj, 'toString'));
// [ false ]  ← inherited

Replaces the older Object.prototype.hasOwnProperty.call(obj, 'a').

Object.groupBy — group by key (ES2024):

const items = [
  { name: 'apple', type: 'fruit' },
  { name: 'carrot', type: 'vegetable' },
  { name: 'banana', type: 'fruit' }
];

const grouped = Object.groupBy(items, item => item.type);
console.log(grouped);
// [ {
//     fruit: [ { name: 'apple', type: 'fruit' }, { name: 'banana', type: 'fruit' } ],
//     vegetable: [ { name: 'carrot', type: 'vegetable' } ]
//   } ]

Object.groupBy with primitives:

const nums = [1, 2, 3, 4, 5];
const parity = Object.groupBy(nums, n => n % 2 === 0 ? 'even' : 'odd');

console.log(parity);
// [ { odd: [ 1, 3, 5 ], even: [ 2, 4 ] } ]

Complete Example Session

// ============================================
// PART 1: OBJECT.KEYS
// ============================================

const obj = { a: 1, b: 2, c: 3 };
console.log(Object.keys(obj));
// [ [ 'a', 'b', 'c' ] ]

// ============================================
// PART 2: OBJECT.VALUES
// ============================================

console.log(Object.values(obj));
// [ [ 1, 2, 3 ] ]

// ============================================
// PART 3: OBJECT.ENTRIES
// ============================================

console.log(Object.entries(obj));
// [ [ [ 'a', 1 ], [ 'b', 2 ], [ 'c', 3 ] ] ]

// ============================================
// PART 4: OBJECT.FROMENTRIES
// ============================================

const back = Object.fromEntries([['a', 1], ['b', 2]]);
console.log(back);
// [ { a: 1, b: 2 } ]

// ============================================
// PART 5: OBJECT.ASSIGN
// ============================================

console.log(Object.assign({}, obj, { d: 4 }));
// [ { a: 1, b: 2, c: 3, d: 4 } ]

// ============================================
// PART 6: OBJECT.FREEZE
// ============================================

const frozen = Object.freeze({ a: 1 });
frozen.a = 2;
console.log(frozen.a);
// [ 1 ]

console.log(Object.isFrozen(frozen));
// [ true ]

// ============================================
// PART 7: OBJECT.SEAL
// ============================================

const sealed = Object.seal({ a: 1 });
sealed.a = 2;
sealed.b = 3;
console.log(sealed);
// [ { a: 2 } ]

console.log(Object.isSealed(sealed));
// [ true ]

// ============================================
// PART 8: OBJECT.HASOWN
// ============================================

console.log(Object.hasOwn(obj, 'a'));
// [ true ]

console.log(Object.hasOwn(obj, 'toString'));
// [ false ]

// ============================================
// PART 9: OBJECT.CREATE
// ============================================

const nullProto = Object.create(null);
nullProto.key = 'value';
console.log(nullProto.toString);
// [ undefined ]

// ============================================
// PART 10: OBJECT.DEFINEPROPERTY
// ============================================

const defined = {};
Object.defineProperty(defined, 'x', { value: 42, writable: false });
console.log(defined.x);
// [ 42 ]

defined.x = 99;
console.log(defined.x);
// [ 42 ]

// ============================================
// PART 11: OBJECT.GETOWNPROPERTYDESCRIPTOR
// ============================================

console.log(Object.getOwnPropertyDescriptor({ a: 1 }, 'a'));
// [ { value: 1, writable: true, enumerable: true, configurable: true } ]

// ============================================
// PART 12: OBJECT.IS
// ============================================

console.log(Object.is(NaN, NaN));
// [ true ]

console.log(Object.is(+0, -0));
// [ false ]

// ============================================
// PART 13: OBJECT.GETPROTOTYPEOF
// ============================================

const arr = [1, 2, 3];
console.log(Object.getPrototypeOf(arr) === Array.prototype);
// [ true ]

// ============================================
// PART 14: OBJECT.SETPROTOTYPEOF
// ============================================

const proto = { greet() { return 'hi'; } };
const o = {};
Object.setPrototypeOf(o, proto);
console.log(o.greet());
// [ 'hi' ]

// ============================================
// PART 15: ITERATE WITH ENTRIES
// ============================================

const prices = { apple: 1.5, banana: 0.75 };

for (const [fruit, price] of Object.entries(prices)) {
  console.log(`${fruit}: $${price}`);
}
// [ apple: $1.5 ]
// [ banana: $0.75 ]

// ============================================
// PART 16: MAP OVER ENTRIES
// ============================================

const doubled = Object.fromEntries(
  Object.entries(prices).map(([k, v]) => [k, v * 2])
);
console.log(doubled);
// [ { apple: 3, banana: 1.5 } ]

// ============================================
// PART 17: FILTER ENTRIES
// ============================================

const mixed = { a: 1, b: null, c: 3, d: undefined };
const clean = Object.fromEntries(
  Object.entries(mixed).filter(([_, v]) => v != null)
);
console.log(clean);
// [ { a: 1, c: 3 } ]

// ============================================
// PART 18: OBJECT.GROUPBY
// ============================================

const items = [
  { name: 'apple', type: 'fruit' },
  { name: 'carrot', type: 'vegetable' },
  { name: 'banana', type: 'fruit' }
];

const grouped = Object.groupBy(items, item => item.type);
console.log(Object.keys(grouped));
// [ [ 'fruit', 'vegetable' ] ]

// ============================================
// PART 19: DEEP FREEZE
// ============================================

function deepFreeze(obj) {
  Object.freeze(obj);
  Object.values(obj).forEach(v => {
    if (v && typeof v === 'object') deepFreeze(v);
  });
  return obj;
}

const nested = deepFreeze({ a: { b: 1 } });
nested.a.b = 99;
console.log(nested.a.b);
// [ 1 ]

// ============================================
// PART 20: FULL SCRIPT
// ============================================

const obj46 = { a: 1, b: 2, c: 3 };

Object.keys(obj46);
Object.values(obj46);
Object.entries(obj46);
Object.fromEntries([['a', 1], ['b', 2]]);
Object.assign({}, obj46, { d: 4 });
Object.freeze(obj46);
Object.seal(obj46);
Object.isFrozen(obj46);
Object.isSealed(obj46);
Object.hasOwn(obj46, 'a');
Object.create(null);
Object.defineProperty(obj46, 'x', { value: 42 });
Object.getOwnPropertyDescriptor(obj46, 'a');
Object.getPrototypeOf(obj46);
Object.setPrototypeOf(obj46, null);
Object.is(1, 1);
Object.is(NaN, NaN);
Object.groupBy([1, 2, 3, 4], n => n % 2 === 0 ? 'even' : 'odd');

Quick Reference

Enumerating

MethodReturns
Object.keys(obj)Keys
Object.values(obj)Values
Object.entries(obj)[key, value] pairs
Object.fromEntries(arr)Object

Copying / Merging

MethodPurpose
Object.assign(target, ...sources)Copy/merge (mutates target)
{ ...obj1, ...obj2 }Spread merge (new object)
structuredClone(obj)Deep copy

Freezing / Sealing

MethodAddModifyDelete
Object.freeze
Object.seal
Object.preventExtensions

Checking

MethodPurpose
Object.isFrozen(obj)Fully frozen?
Object.isSealed(obj)Sealed?
Object.isExtensible(obj)Can add props?
Object.hasOwn(obj, k)Own property?

Properties

MethodPurpose
Object.definePropertyDefine one
Object.definePropertiesDefine many
Object.getOwnPropertyDescriptorGet descriptor
Object.getOwnPropertyDescriptorsGet all

Prototypes

MethodPurpose
Object.create(proto)Create with proto
Object.create(null)No prototype
Object.getPrototypeOf(obj)Get prototype
Object.setPrototypeOf(obj, p)Set prototype

Comparison

MethodPurpose
Object.is(a, b)Same-value equality
Object.is(NaN, NaN)true
Object.is(+0, -0)false

Grouping (ES2024)

MethodPurpose
Object.groupBy(arr, fn)Group into object
Map.groupBy(arr, fn)Group into Map

Descriptor Flags

FlagMeaning
valueValue
writableCan change
enumerableVisible
configurableCan delete/redefine
getGetter
setSetter

Best Practices

Do This:

// Use Object.entries for iteration
for (const [k, v] of Object.entries(obj)) { }   // ✅

// Use spread for merging
const merged = { ...a, ...b };                  // ✅

// Use Object.fromEntries for transforms
Object.fromEntries(Object.entries(o).map(...)); // ✅

// Use Object.freeze for constants
const CONFIG = Object.freeze({ ... });          // ✅

// Use Object.hasOwn for own-property check
Object.hasOwn(obj, 'key');                      // ✅

// Use Object.create(null) for dictionaries
const dict = Object.create(null);               // ✅

// Use structuredClone for deep copies
const deep = structuredClone(obj);              // ✅

// Use Object.is for NaN / -0 comparisons
Object.is(NaN, NaN);                            // ✅

// Use Object.groupBy for grouping (ES2024)
Object.groupBy(items, i => i.type);             // ✅

Don’t Do This:

// Don't use for...in for own properties
for (const k in obj) { }                        // ⚠️  includes inherited

// Don't use Object.assign without target
Object.assign(source);                          // ❌ returns source
Object.assign({}, source);                      // ✅

// Don't expect deep freeze
Object.freeze({ a: { b: 1 } });                 // ⚠️  shallow
// obj.a.b = 99 works

// Don't use getPrototypeOf in hot loops
Object.getPrototypeOf(obj);                     // ⚠️  slow

// Don't use setPrototypeOf
Object.setPrototypeOf(obj, proto);              // ⚠️  deoptimizes

// Don't rely on key order for symbols
Object.keys(obj);                               // ❌ excludes symbols

// Don't check NaN with ===
NaN === NaN;                                    // ❌ always false
Object.is(NaN, NaN);                            // ✅

// Don't use Object.assign for deep merge
Object.assign({}, nested);                      // ❌ shallow only

Common Pitfalls

PitfallProblemSolution
Object.assign mutates targetOriginal changedUse {} target or spread
freeze is shallowNested still mutabledeepFreeze or structuredClone
for...in includes inheritedUnexpected keysUse Object.keys
Object.keys excludes symbolsMissing keysUse Object.getOwnPropertySymbols
Key order for integer-likeSorted numericallyKnown behavior
setPrototypeOf slowPerformance hitSet prototype at creation
defineProperty non-writableSilent failure in sloppy modeSet writable: true or use strict
Object.is on objectsCompares referencesSame as ===

Real-World Examples

1. Object.keys

console.log(Object.keys({ a: 1, b: 2 }));
// [ [ 'a', 'b' ] ]

2. Object.values

console.log(Object.values({ a: 1, b: 2 }));
// [ [ 1, 2 ] ]

3. Object.entries

console.log(Object.entries({ a: 1, b: 2 }));
// [ [ [ 'a', 1 ], [ 'b', 2 ] ] ]

4. Object.fromEntries

console.log(Object.fromEntries([['a', 1], ['b', 2]]));
// [ { a: 1, b: 2 } ]

5. Object.assign

console.log(Object.assign({}, { a: 1 }, { b: 2 }));
// [ { a: 1, b: 2 } ]

6. Object.freeze

const config = Object.freeze({ port: 8080 });
config.port = 9090;
console.log(config.port);
// [ 8080 ]

7. Object.seal

const user = Object.seal({ name: 'Alice' });
user.name = 'Bob';
user.age = 30;
console.log(user);
// [ { name: 'Bob' } ]

8. Object.isFrozen

console.log(Object.isFrozen(Object.freeze({})));
// [ true ]

9. Object.hasOwn

console.log(Object.hasOwn({ a: 1 }, 'a'));
// [ true ]

console.log(Object.hasOwn({ a: 1 }, 'toString'));
// [ false ]

10. Object.create(null)

const dict = Object.create(null);
dict.key = 'value';
console.log(dict.toString);
// [ undefined ]

11. Object.defineProperty

const obj = {};
Object.defineProperty(obj, 'x', { value: 42, writable: false });
console.log(obj.x);
// [ 42 ]

12. Object.getOwnPropertyDescriptor

const desc = Object.getOwnPropertyDescriptor({ a: 1 }, 'a');
console.log(desc.writable);
// [ true ]

13. Object.getPrototypeOf

console.log(Object.getPrototypeOf([]) === Array.prototype);
// [ true ]

14. Object.setPrototypeOf

const proto = { greet() { return 'hi'; } };
const obj = {};
Object.setPrototypeOf(obj, proto);
console.log(obj.greet());
// [ 'hi' ]

15. Object.is

console.log(Object.is(NaN, NaN));
// [ true ]

console.log(Object.is(+0, -0));
// [ false ]

16. Object.groupBy

const nums = [1, 2, 3, 4];
const grouped = Object.groupBy(nums, n => n % 2 === 0 ? 'even' : 'odd');
console.log(grouped);
// [ { odd: [ 1, 3 ], even: [ 2, 4 ] } ]

17. Iterate with entries

const prices = { apple: 1.5, banana: 0.75 };

for (const [fruit, price] of Object.entries(prices)) {
  console.log(`${fruit}: $${price}`);
}
// [ apple: $1.5 ]
// [ banana: $0.75 ]

18. Map over entries

const doubled = Object.fromEntries(
  Object.entries({ a: 1, b: 2 }).map(([k, v]) => [k, v * 2])
);
console.log(doubled);
// [ { a: 2, b: 4 } ]

19. Filter entries

const mixed = { a: 1, b: null, c: 3 };
const clean = Object.fromEntries(
  Object.entries(mixed).filter(([_, v]) => v != null)
);
console.log(clean);
// [ { a: 1, c: 3 } ]

20. Full Script

const obj46 = { a: 1, b: 2, c: 3 };

Object.keys(obj46);
Object.values(obj46);
Object.entries(obj46);
Object.fromEntries([['a', 1], ['b', 2]]);
Object.assign({}, obj46, { d: 4 });
Object.freeze(obj46);
Object.seal(obj46);
Object.isFrozen(obj46);
Object.isSealed(obj46);
Object.hasOwn(obj46, 'a');
Object.create(null);
Object.defineProperty(obj46, 'x', { value: 42 });
Object.getOwnPropertyDescriptor(obj46, 'a');
Object.getPrototypeOf(obj46);
Object.setPrototypeOf(obj46, null);
Object.is(1, 1);
Object.is(NaN, NaN);
Object.groupBy([1, 2, 3, 4], n => n % 2 === 0 ? 'even' : 'odd');

Visual: Object Methods by Category

┌──────────────────────────────────────────────┐
│  ENUMERATE                                   │
│                                              │
│  Object.keys      → [ 'a', 'b' ]             │
│  Object.values    → [ 1, 2 ]                 │
│  Object.entries   → [ ['a', 1], ['b', 2] ]   │
│  Object.fromEntries ← reverse                │
│                                              │
└──────────────────────────────────────────────┘

┌──────────────────────────────────────────────┐
│  COPY / MERGE                                │
│                                              │
│  Object.assign({}, a, b)                     │
│  { ...a, ...b }                              │
│  structuredClone(obj)                        │
│                                              │
└──────────────────────────────────────────────┘

┌──────────────────────────────────────────────┐
│  IMMUTABILITY                                │
│                                              │
│  Object.freeze   → no add/modify/delete      │
│  Object.seal     → modify only               │
│  preventExtensions → no add                  │
│  Object.isFrozen / isSealed / isExtensible   │
│                                              │
└──────────────────────────────────────────────┘

┌──────────────────────────────────────────────┐
│  INSPECT                                     │
│                                              │
│  Object.hasOwn(obj, k)                       │
│  Object.getPrototypeOf(obj)                  │
│  Object.getOwnPropertyDescriptor(obj, k)     │
│                                              │
└──────────────────────────────────────────────┘

┌──────────────────────────────────────────────┐
│  COMPARE / GROUP                             │
│                                              │
│  Object.is(a, b)                             │
│  Object.groupBy(arr, fn)                     │
│                                              │
└──────────────────────────────────────────────┘

Visual: Object.freeze vs Object.seal

┌──────────────────────────────────────────────┐
│           Object.freeze                      │
│                                              │
│  Add    ❌                                    │
│  Modify ❌                                    │
│  Delete ❌                                    │
│                                              │
│  Fully immutable — safe for constants        │
│                                              │
└──────────────────────────────────────────────┘

┌──────────────────────────────────────────────┐
│           Object.seal                        │
│                                              │
│  Add    ❌                                    │
│  Modify ✅                                    │
│  Delete ❌                                    │
│                                              │
│  Fixed shape, mutable values                 │
│                                              │
└──────────────────────────────────────────────┘

┌──────────────────────────────────────────────┐
│           Object.preventExtensions           │
│                                              │
│  Add    ❌                                    │
│  Modify ✅                                    │
│  Delete ✅                                    │
│                                              │
│  No new keys — existing keys fully mutable   │
│                                              │
└──────────────────────────────────────────────┘

Summary

MethodCategoryPurpose
Object.keysEnumerateKeys
Object.valuesEnumerateValues
Object.entriesEnumeratePairs
Object.fromEntriesEnumerateFrom pairs
Object.assignCopyMerge (mutates target)
structuredCloneCopyDeep copy
Object.freezeImmutabilityFully frozen
Object.sealImmutabilityModify only
Object.preventExtensionsImmutabilityNo add
Object.isFrozenImmutabilityCheck frozen
Object.isSealedImmutabilityCheck sealed
Object.isExtensibleImmutabilityCan add
Object.hasOwnInspectOwn property
Object.createCreateWith prototype
Object.definePropertyCreatePrecise descriptor
Object.getOwnPropertyDescriptorInspectGet descriptor
Object.getPrototypeOfInspectGet prototype
Object.setPrototypeOfModifySet prototype
Object.isCompareSame-value
Object.groupByGroupGroup into object

Key takeaways:

  • Object.keys/values/entries enumerate own enumerable properties
  • Object.fromEntries is the reverse — perfect for Map/Object conversions
  • Object.assign mutates the target — use {} or spread for a new object
  • Object.freeze is shallow — nested objects still mutable; use deepFreeze or structuredClone
  • Object.seal prevents add/delete but allows modify
  • Object.hasOwn (ES2022) replaces hasOwnProperty.call
  • Object.is differs from === for NaN and ±0
  • Object.create(null) gives a clean dictionary with no prototype
  • Object.defineProperty enables getters, setters, non-writable props
  • Object.groupBy (ES2024) groups an array by a key function
  • Use for...of with Object.entries rather than for...in to avoid inherited keys
  • Use structuredClone for a true deep copy — Object.assign and spread are shallow

Remember: Object is the toolbox for working with objects. Enumerate with keys/values/entries, copy with spread or structuredClone, lock with freeze/seal, inspect with hasOwn/getPrototypeOf/getOwnPropertyDescriptor, compare with Object.is, and group with Object.groupBy. Know the difference between shallow and deep, between enumerable and not, between own and inherited. Master Object.* methods, and you have full control over JavaScript’s most fundamental data structure.


Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!