JavaScript Object Manipulation Cheat Sheet

JavaScript Object Manipulation Cheatsheet

Object Creation

Basic Object Creation

// Object literal
const person = {
    name: 'John',
    age: 30,
    greet() {
        return `Hello, I'm ${this.name}`;
    }
};

// Constructor function
function Person(name, age) {
    this.name = name;
    this.age = age;
}
const john = new Person('John', 30);

// Class syntax
class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    greet() {
        return `Hello, I'm ${this.name}`;
    }
}

// Object.create()
const personProto = {
    greet() {
        return `Hello, I'm ${this.name}`;
    }
};
const person = Object.create(personProto, {
    name: { value: 'John', writable: true },
    age: { value: 30, writable: true }
});

Property Descriptors

// Define property with descriptor
Object.defineProperty(person, 'id', {
    value: 1,
    writable: false,
    enumerable: true,
    configurable: false
});

// Define multiple properties
Object.defineProperties(person, {
    id: {
        value: 1,
        writable: false
    },
    email: {
        get() { return this._email; },
        set(value) { this._email = value.toLowerCase(); }
    }
});

// Get property descriptor
const descriptor = Object.getOwnPropertyDescriptor(person, 'name');
console.log(descriptor); // { value: 'John', writable: true, enumerable: true, configurable: true }

Object Access and Modification

Property Access

const user = {
    name: 'John',
    age: 30,
    address: {
        city: 'NYC',
        country: 'USA'
    }
};

// Dot notation
console.log(user.name); // 'John'

// Bracket notation
console.log(user['name']); // 'John'
const property = 'age';
console.log(user[property]); // 30

// Optional chaining
console.log(user?.address?.city); // 'NYC'
console.log(user?.phone?.number); // undefined

// Nullish coalescing
const name = user.name ?? 'Unknown'; // 'John'
const phone = user.phone ?? 'No phone'; // 'No phone'

Adding and Removing Properties

const person = { name: 'John' };

// Add properties
person.age = 30;
person['email'] = 'john@example.com';
Object.assign(person, { city: 'NYC', country: 'USA' });

// Remove properties
delete person.age;
delete person['email'];

// Check if property exists
console.log('name' in person); // true
console.log(person.hasOwnProperty('name')); // true
console.log(Object.prototype.hasOwnProperty.call(person, 'name')); // true (safer)

Property Enumeration

const person = {
    name: 'John',
    age: 30,
    [Symbol('id')]: 123
};

// Get all keys
console.log(Object.keys(person)); // ['name', 'age']

// Get all values
console.log(Object.values(person)); // ['John', 30]

// Get all entries
console.log(Object.entries(person)); // [['name', 'John'], ['age', 30]]

// Get all property names (including symbols)
console.log(Object.getOwnPropertyNames(person)); // ['name', 'age']
console.log(Object.getOwnPropertySymbols(person)); // [Symbol(id)]

// Iterate over properties
for (const key in person) {
    if (person.hasOwnProperty(key)) {
        console.log(`${key}: ${person[key]}`);
    }
}

Object Cloning

Shallow Cloning

const original = {
    name: 'John',
    age: 30,
    address: { city: 'NYC' }
};

// Spread operator
const clone1 = { ...original };

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

// Manual copying
const clone3 = {};
for (const key in original) {
    if (original.hasOwnProperty(key)) {
        clone3[key] = original[key];
    }
}

// Note: Nested objects are still referenced
clone1.address.city = 'LA';
console.log(original.address.city); // 'LA' (changed!)

Deep Cloning

// JSON method (simple but limited)
const deepClone1 = JSON.parse(JSON.stringify(original));

// Recursive function
function deepClone(obj) {
    if (obj === null || typeof obj !== 'object') return obj;
    if (obj instanceof Date) return new Date(obj.getTime());
    if (obj instanceof Array) return obj.map(item => deepClone(item));
    
    const cloned = {};
    for (const key in obj) {
        if (obj.hasOwnProperty(key)) {
            cloned[key] = deepClone(obj[key]);
        }
    }
    return cloned;
}

// Structured clone (modern browsers)
const deepClone2 = structuredClone(original);

// Lodash cloneDeep (if using lodash)
const deepClone3 = _.cloneDeep(original);

Selective Cloning

// Clone with specific properties
const { name, age } = original;
const partialClone = { name, age };

// Clone excluding specific properties
const { address, ...cloneWithoutAddress } = original;

// Clone with transformations
const transformedClone = Object.fromEntries(
    Object.entries(original).map(([key, value]) => [
        key,
        typeof value === 'string' ? value.toUpperCase() : value
    ])
);

Object Merging

Basic Merging

const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, c: 4 };

// Object.assign() (mutates first object)
const merged1 = Object.assign({}, obj1, obj2); // { a: 1, b: 3, c: 4 }

// Spread operator
const merged2 = { ...obj1, ...obj2 }; // { a: 1, b: 3, c: 4 }

// Multiple objects
const obj3 = { d: 5 };
const merged3 = { ...obj1, ...obj2, ...obj3 }; // { a: 1, b: 3, c: 4, d: 5 }

Deep Merging

function deepMerge(target, source) {
    const result = { ...target };
    
    for (const key in source) {
        if (source.hasOwnProperty(key)) {
            if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
                result[key] = deepMerge(result[key] || {}, source[key]);
            } else {
                result[key] = source[key];
            }
        }
    }
    
    return result;
}

const obj1 = { a: 1, b: { x: 1, y: 2 } };
const obj2 = { b: { y: 3, z: 4 }, c: 5 };
const deepMerged = deepMerge(obj1, obj2);
// { a: 1, b: { x: 1, y: 3, z: 4 }, c: 5 }

Conditional Merging

// Merge with conditions
const baseConfig = { theme: 'dark', language: 'en' };
const userConfig = { theme: 'light' };
const systemConfig = { debug: true };

const finalConfig = {
    ...baseConfig,
    ...(userConfig.theme && { theme: userConfig.theme }),
    ...(process.env.NODE_ENV === 'development' && systemConfig)
};

Object Transformation

Mapping and Filtering

const users = [
    { id: 1, name: 'John', age: 30 },
    { id: 2, name: 'Jane', age: 25 },
    { id: 3, name: 'Bob', age: 35 }
];

// Transform array of objects
const userNames = users.map(user => user.name);
const adults = users.filter(user => user.age >= 30);

// Transform object to array
const userMap = {
    'user1': { name: 'John', age: 30 },
    'user2': { name: 'Jane', age: 25 }
};

const userArray = Object.entries(userMap).map(([id, user]) => ({
    id,
    ...user
}));

// Transform array to object
const userById = users.reduce((acc, user) => {
    acc[user.id] = user;
    return acc;
}, {});

Object Grouping

const products = [
    { name: 'Laptop', category: 'Electronics', price: 999 },
    { name: 'Book', category: 'Books', price: 15 },
    { name: 'Phone', category: 'Electronics', price: 699 }
];

// Group by category
const groupedByCategory = products.reduce((acc, product) => {
    if (!acc[product.category]) {
        acc[product.category] = [];
    }
    acc[product.category].push(product);
    return acc;
}, {});

// Group with aggregation
const categoryStats = products.reduce((acc, product) => {
    if (!acc[product.category]) {
        acc[product.category] = { count: 0, totalPrice: 0 };
    }
    acc[product.category].count++;
    acc[product.category].totalPrice += product.price;
    return acc;
}, {});

Prototype and Inheritance

Prototype Chain

// Constructor function
function Animal(name) {
    this.name = name;
}

Animal.prototype.speak = function() {
    return `${this.name} makes a sound`;
};

// Inheritance
function Dog(name, breed) {
    Animal.call(this, name);
    this.breed = breed;
}

Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

Dog.prototype.speak = function() {
    return `${this.name} barks`;
};

// Class inheritance
class Animal {
    constructor(name) {
        this.name = name;
    }
    
    speak() {
        return `${this.name} makes a sound`;
    }
}

class Dog extends Animal {
    constructor(name, breed) {
        super(name);
        this.breed = breed;
    }
    
    speak() {
        return `${this.name} barks`;
    }
}

Prototype Methods

const person = { name: 'John', age: 30 };

// Check prototype
console.log(Object.getPrototypeOf(person)); // Object.prototype
console.log(person.__proto__); // Object.prototype (deprecated)

// Set prototype
const animalProto = { speak() { return 'sound'; } };
const dog = Object.create(animalProto);

// Check if property is own or inherited
console.log(person.hasOwnProperty('name')); // true
console.log(person.hasOwnProperty('toString')); // false

// Get all properties (own + inherited)
function getAllProperties(obj) {
    const props = [];
    let current = obj;
    
    while (current) {
        props.push(...Object.getOwnPropertyNames(current));
        current = Object.getPrototypeOf(current);
    }
    
    return [...new Set(props)];
}

Object Utilities

Validation and Type Checking

// Type checking
function isObject(value) {
    return value !== null && typeof value === 'object' && !Array.isArray(value);
}

function isEmpty(obj) {
    return Object.keys(obj).length === 0;
}

function hasNestedProperty(obj, path) {
    return path.split('.').every(prop => obj && obj.hasOwnProperty(prop));
}

// Usage
const user = { profile: { name: 'John' } };
console.log(hasNestedProperty(user, 'profile.name')); // true
console.log(hasNestedProperty(user, 'profile.age')); // false

Object Comparison

function deepEqual(obj1, obj2) {
    if (obj1 === obj2) return true;
    if (obj1 == null || obj2 == null) return false;
    if (typeof obj1 !== 'object' || typeof obj2 !== 'object') return false;
    
    const keys1 = Object.keys(obj1);
    const keys2 = Object.keys(obj2);
    
    if (keys1.length !== keys2.length) return false;
    
    return keys1.every(key => keys2.includes(key) && deepEqual(obj1[key], obj2[key]));
}

// Usage
const obj1 = { a: 1, b: { c: 2 } };
const obj2 = { a: 1, b: { c: 2 } };
console.log(deepEqual(obj1, obj2)); // true

Object Serialization

// Safe JSON serialization
function safeStringify(obj, replacer = null, space = 2) {
    try {
        return JSON.stringify(obj, replacer, space);
    } catch (error) {
        console.error('Serialization failed:', error);
        return null;
    }
}

// Custom replacer function
function replacer(key, value) {
    if (typeof value === 'function') {
        return '[Function]';
    }
    if (value === undefined) {
        return '[Undefined]';
    }
    return value;
}

// Usage
const obj = { 
    name: 'John', 
    age: 30, 
    greet: function() {}, 
    undef: undefined 
};
console.log(safeStringify(obj, replacer));

Performance Considerations

Object Pooling

class ObjectPool {
    constructor(createFn, resetFn, initialSize = 10) {
        this.pool = [];
        this.createFn = createFn;
        this.resetFn = resetFn;
        
        // Pre-populate pool
        for (let i = 0; i < initialSize; i++) {
            this.pool.push(createFn());
        }
    }
    
    get() {
        return this.pool.pop() || this.createFn();
    }
    
    release(obj) {
        this.resetFn(obj);
        this.pool.push(obj);
    }
}

// Usage
const vectorPool = new ObjectPool(
    () => ({ x: 0, y: 0 }),
    (vector) => { vector.x = 0; vector.y = 0; }
);

Efficient Property Access

// Cache property access for performance
const user = { name: 'John', age: 30 };
const name = user.name; // Cache if used frequently

// Use Map for frequent lookups
const userMap = new Map();
userMap.set('user1', { name: 'John', age: 30 });
console.log(userMap.get('user1')); // O(1) lookup

// Avoid creating objects in hot paths
function optimizedFunction(x, y) {
    // ❌ Bad: creates new object each time
    return { x: x * 2, y: y * 2 };
    
    // ✅ Good: reuse object
    result.x = x * 2;
    result.y = y * 2;
    return result;
}