JavaScript Object Methods Complete Guide

Master Object static methods, property operations, object traversal, and practical techniques

JavaScript Object Methods Complete Guide

Objects are the core data structure in JavaScript. This article covers various methods and techniques for object manipulation.

Creating Objects

Basic Methods

// Literal (most common)
const obj = { name: 'Alice', age: 25 };

// Constructor
const obj2 = new Object();
obj2.name = 'Bob';

// Object.create (specify prototype)
const proto = { greet() { return `Hello, ${this.name}`; } };
const obj3 = Object.create(proto);
obj3.name = 'Charlie';
obj3.greet();  // 'Hello, Charlie'

// Object.create(null) (no prototype)
const pureObj = Object.create(null);
// pureObj.toString  // undefined

Object.assign

// Merge objects
const target = { a: 1 };
const source = { b: 2, c: 3 };
Object.assign(target, source);
// target = { a: 1, b: 2, c: 3 }

// Merge multiple objects
const merged = Object.assign({}, obj1, obj2, obj3);

// Shallow copy
const copy = Object.assign({}, original);

// Later properties override earlier ones
const defaults = { host: 'localhost', port: 3000 };
const options = { port: 8080 };
const config = Object.assign({}, defaults, options);
// { host: 'localhost', port: 8080 }

// Note: Only copies enumerable own properties

Object.fromEntries

// Create object from key-value pair array
const entries = [['name', 'Alice'], ['age', 25]];
const obj = Object.fromEntries(entries);
// { name: 'Alice', age: 25 }

// Create object from Map
const map = new Map([['a', 1], ['b', 2]]);
const fromMap = Object.fromEntries(map);
// { a: 1, b: 2 }

// Transform object with Object.entries
const original = { a: 1, b: 2, c: 3 };
const doubled = Object.fromEntries(
  Object.entries(original).map(([k, v]) => [k, v * 2])
);
// { a: 2, b: 4, c: 6 }

Property Operations

Property Access

const obj = { name: 'Alice', 'full-name': 'Alice Smith' };

// Dot notation
obj.name;  // 'Alice'

// Bracket notation (supports dynamic keys)
obj['name'];           // 'Alice'
obj['full-name'];      // 'Alice Smith'

const key = 'name';
obj[key];              // 'Alice'

// Optional chaining
const user = { address: { city: 'NYC' } };
user?.address?.city;   // 'NYC'
user?.contact?.email;  // undefined (no error)

Property Checking

const obj = { name: 'Alice', age: 25 };

// in operator (includes inherited)
'name' in obj;       // true
'toString' in obj;   // true

// hasOwnProperty (own properties only)
obj.hasOwnProperty('name');     // true
obj.hasOwnProperty('toString'); // false

// Object.hasOwn (ES2022, recommended)
Object.hasOwn(obj, 'name');     // true
Object.hasOwn(obj, 'toString'); // false

// Checking property value
obj.email !== undefined;  // Unreliable
'email' in obj;           // Reliable

Property Definition

const obj = {};

// Object.defineProperty (single property)
Object.defineProperty(obj, 'name', {
  value: 'Alice',
  writable: true,      // Can be changed
  enumerable: true,    // Shows in enumeration
  configurable: true   // Can be configured
});

// Object.defineProperties (multiple properties)
Object.defineProperties(obj, {
  name: {
    value: 'Alice',
    writable: true
  },
  age: {
    value: 25,
    writable: false  // Read-only
  }
});

// getter and setter
Object.defineProperty(obj, 'fullName', {
  get() {
    return `${this.firstName} ${this.lastName}`;
  },
  set(value) {
    [this.firstName, this.lastName] = value.split(' ');
  }
});

Property Descriptors

const obj = { name: 'Alice' };

// Get single property descriptor
Object.getOwnPropertyDescriptor(obj, 'name');
// { value: 'Alice', writable: true, enumerable: true, configurable: true }

// Get all property descriptors
Object.getOwnPropertyDescriptors(obj);
// { name: { value: 'Alice', writable: true, ... } }

// Complete object copy (including descriptors)
const clone = Object.defineProperties(
  {},
  Object.getOwnPropertyDescriptors(original)
);

Object Traversal

Object.keys / values / entries

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

// Get keys array
Object.keys(obj);    // ['a', 'b', 'c']

// Get values array
Object.values(obj);  // [1, 2, 3]

// Get key-value pair array
Object.entries(obj); // [['a', 1], ['b', 2], ['c', 3]]

// Iterate object
Object.entries(obj).forEach(([key, value]) => {
  console.log(`${key}: ${value}`);
});

// Using for...of
for (const [key, value] of Object.entries(obj)) {
  console.log(`${key}: ${value}`);
}

for…in Loop

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

// for...in iteration (includes inherited enumerable)
for (const key in obj) {
  console.log(key, obj[key]);
}

// Iterate own properties only
for (const key in obj) {
  if (Object.hasOwn(obj, key)) {
    console.log(key, obj[key]);
  }
}

Getting Property Names

const sym = Symbol('id');
const obj = {
  name: 'Alice',
  [sym]: 123
};

Object.defineProperty(obj, 'hidden', {
  value: 'secret',
  enumerable: false
});

// Enumerable own properties
Object.keys(obj);                  // ['name']

// All own properties (including non-enumerable)
Object.getOwnPropertyNames(obj);   // ['name', 'hidden']

// Symbol properties
Object.getOwnPropertySymbols(obj); // [Symbol(id)]

// All own properties (string + Symbol)
Reflect.ownKeys(obj);              // ['name', 'hidden', Symbol(id)]

Object Protection

Object.freeze

const obj = { name: 'Alice', address: { city: 'NYC' } };

// Freeze object (no modify, add, delete)
Object.freeze(obj);

obj.name = 'Bob';     // Silently fails (error in strict mode)
obj.age = 25;         // Won't add
delete obj.name;      // Won't delete

console.log(obj.name);  // 'Alice'

// Check if frozen
Object.isFrozen(obj);   // true

// Note: Shallow freeze
obj.address.city = 'LA';  // Still modifiable
console.log(obj.address.city);  // 'LA'

// Deep freeze function
function deepFreeze(obj) {
  Object.freeze(obj);
  Object.values(obj).forEach(value => {
    if (typeof value === 'object' && value !== null) {
      deepFreeze(value);
    }
  });
  return obj;
}

Object.seal

const obj = { name: 'Alice' };

// Seal object (can modify, no add/delete)
Object.seal(obj);

obj.name = 'Bob';     // OK
obj.age = 25;         // Won't add
delete obj.name;      // Won't delete

// Check if sealed
Object.isSealed(obj);  // true

Object.preventExtensions

const obj = { name: 'Alice' };

// Prevent extensions (can modify/delete, no add)
Object.preventExtensions(obj);

obj.name = 'Bob';     // OK
delete obj.name;      // OK
obj.age = 25;         // Won't add

// Check if extensible
Object.isExtensible(obj);  // false

Protection Level Comparison

Object Protection Levels:
┌─────────────────────────────────────────────────────┐
│                                                     │
│   Method              Add   Delete  Modify  Config  │
│   ├── preventExtensions  ✗     ✓       ✓      ✓    │
│   ├── seal              ✗     ✗       ✓      ✗    │
│   └── freeze            ✗     ✗       ✗      ✗    │
│                                                     │
└─────────────────────────────────────────────────────┘

Object Comparison

Equality Checking

// Object.is (strict equality, handles edge cases)
Object.is(1, 1);              // true
Object.is(NaN, NaN);          // true (=== is false)
Object.is(0, -0);             // false (=== is true)

// === strict equality
1 === 1;      // true
NaN === NaN;  // false
0 === -0;     // true

// Object reference comparison
const obj1 = { a: 1 };
const obj2 = { a: 1 };
obj1 === obj2;        // false (different references)

const obj3 = obj1;
obj1 === obj3;        // true (same reference)

Deep Comparison

// Simple deep comparison
function deepEqual(obj1, obj2) {
  if (obj1 === obj2) return true;

  if (typeof obj1 !== 'object' || typeof obj2 !== 'object') {
    return false;
  }

  if (obj1 === null || obj2 === null) return false;

  const keys1 = Object.keys(obj1);
  const keys2 = Object.keys(obj2);

  if (keys1.length !== keys2.length) return false;

  return keys1.every(key =>
    Object.hasOwn(obj2, key) && deepEqual(obj1[key], obj2[key])
  );
}

// Usage
deepEqual({ a: 1, b: { c: 2 } }, { a: 1, b: { c: 2 } });  // true

Practical Techniques

Object Destructuring

const user = { name: 'Alice', age: 25, city: 'NYC' };

// Basic destructuring
const { name, age } = user;

// Renaming
const { name: userName } = user;

// Default values
const { country = 'USA' } = user;

// Rest properties
const { name, ...rest } = user;
// rest = { age: 25, city: 'NYC' }

Conditional Properties

const condition = true;

// Conditionally add properties
const obj = {
  always: true,
  ...(condition && { sometimes: true })
};

// Or use ternary
const obj2 = {
  ...(condition ? { a: 1 } : { b: 2 })
};

Dynamic Key Names

const key = 'name';
const value = 'Alice';

// Computed property names
const obj = {
  [key]: value,
  [`${key}Length`]: value.length
};
// { name: 'Alice', nameLength: 5 }

Object Method Shorthand

// ES6 method shorthand
const obj = {
  name: 'Alice',

  // Method shorthand
  greet() {
    return `Hello, ${this.name}`;
  },

  // getter/setter
  get upperName() {
    return this.name.toUpperCase();
  },

  set lowerName(value) {
    this.name = value.toLowerCase();
  }
};

Removing Properties

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

// delete operator
delete obj.a;

// Destructuring (doesn't modify original)
const { b, ...rest } = obj;
// rest = { a: 1, c: 3 }

// Filter multiple properties
const omit = (obj, keys) => Object.fromEntries(
  Object.entries(obj).filter(([k]) => !keys.includes(k))
);

omit(obj, ['a', 'b']);  // { c: 3 }

Best Practices Summary

Object Operation Best Practices:
┌─────────────────────────────────────────────────────┐
│                                                     │
│   Creation and Copying                              │
│   ├── Prefer literal syntax for creation           │
│   ├── Use spread operator for shallow copy         │
│   └── Use structuredClone or libraries for deep    │
│                                                     │
│   Property Operations                               │
│   ├── Use Object.hasOwn to check own properties    │
│   ├── Use optional chaining for safe nested access │
│   └── Use destructuring to simplify extraction     │
│                                                     │
│   Traversal Choices                                 │
│   ├── Object.keys/values/entries most common       │
│   ├── Avoid for...in (includes inherited)          │
│   └── Reflect.ownKeys gets all keys                │
│                                                     │
└─────────────────────────────────────────────────────┘
MethodPurposeReturns
Object.keysGet keysString array
Object.valuesGet valuesValue array
Object.entriesGet key-value pairs2D array
Object.assignMerge objectsTarget object

Master object methods to efficiently manipulate JavaScript data structures.