Skip to content

Object Methods: Mastering the Built-in Toolkit

A professional carpenter's toolbox contains not just basic tools like hammers and saws, but also specialized tools—tape measures for measuring, levels for alignment, and squares for ensuring right angles. Similarly, JavaScript's Object provides a complete set of built-in methods that help us inspect objects, transform data, control properties, and implement complex operations. Mastering these methods is like having a professional toolkit that allows you to handle object data more efficiently.

Object.keys() - Get All Keys

Object.keys() returns an array containing all enumerable property names of an object.

javascript
let user = {
  name: "Alice",
  age: 25,
  email: "[email protected]",
  city: "New York",
};

let keys = Object.keys(user);
console.log(keys); // ["name", "age", "email", "city"]

// Iterate over all keys of the object
Object.keys(user).forEach((key) => {
  console.log(`${key}: ${user[key]}`);
});
// name: Alice
// age: 25
// email: [email protected]
// city: New York

Object.keys() only returns the object's own properties (excluding inherited properties) and only returns enumerable properties. This makes it the standard method for traversing object properties.

Real-world Application: Validating Object Fields

javascript
function validateRequiredFields(obj, requiredFields) {
  let actualFields = Object.keys(obj);
  let missingFields = requiredFields.filter(
    (field) => !actualFields.includes(field)
  );

  if (missingFields.length > 0) {
    return {
      valid: false,
      missing: missingFields,
    };
  }

  return { valid: true };
}

let userInput = {
  username: "johndoe",
  email: "[email protected]",
  // Missing password
};

let result = validateRequiredFields(userInput, [
  "username",
  "email",
  "password",
]);
console.log(result); // { valid: false, missing: ["password"] }

Object Property Counting

javascript
let product = {
  name: "Laptop",
  price: 999,
  brand: "TechBrand",
  inStock: true,
};

console.log(`This object has ${Object.keys(product).length} properties`);
// This object has 4 properties

// Check if object is empty
function isEmpty(obj) {
  return Object.keys(obj).length === 0;
}

console.log(isEmpty({})); // true
console.log(isEmpty(product)); // false

Object.values() - Get All Values

Object.values() returns an array containing all enumerable property values of an object.

javascript
let scores = {
  math: 95,
  english: 88,
  science: 92,
  history: 85,
};

let values = Object.values(scores);
console.log(values); // [95, 88, 92, 85]

// Calculate average score
let average = values.reduce((sum, score) => sum + score, 0) / values.length;
console.log(`Average score: ${average}`); // Average score: 90

Real-world Application: Data Statistics

javascript
let inventory = {
  laptops: 15,
  mice: 50,
  keyboards: 30,
  monitors: 20,
};

// Total inventory quantity
let totalItems = Object.values(inventory).reduce((sum, qty) => sum + qty, 0);
console.log(`Total items in stock: ${totalItems}`); // 115

// Maximum stock quantity
let maxQuantity = Math.max(...Object.values(inventory));
console.log(`Highest stock quantity: ${maxQuantity}`); // 50

// Find product with most stock
let maxStockProduct = Object.keys(inventory).find(
  (key) => inventory[key] === maxQuantity
);
console.log(`Product with most stock: ${maxStockProduct}`); // mice

Object.entries() - Get Key-Value Pairs

Object.entries() returns an array containing all enumerable property key-value pairs of an object.

javascript
let person = {
  name: "Bob",
  age: 30,
  occupation: "Developer",
};

let entries = Object.entries(person);
console.log(entries);
// [
//   ["name", "Bob"],
//   ["age", 30],
//   ["occupation", "Developer"]
// ]

// Iterate over key-value pairs
for (let [key, value] of Object.entries(person)) {
  console.log(`${key}: ${value}`);
}
// name: Bob
// age: 30
// occupation: Developer

Object.entries() is particularly useful when you need to access both keys and values simultaneously. Combined with destructuring assignment, it's very elegant.

Real-world Application: Object Filtering

javascript
function filterObject(obj, predicate) {
  return Object.fromEntries(Object.entries(obj).filter(predicate));
}

let products = {
  laptop: 999,
  mouse: 25,
  keyboard: 75,
  monitor: 299,
  webcam: 89,
};

// Filter products with price below $100
let affordable = filterObject(products, ([key, price]) => price < 100);
console.log(affordable);
// { mouse: 25, keyboard: 75, webcam: 89 }

// Filter products whose names contain "key"
let withKey = filterObject(products, ([name, price]) => name.includes("key"));
console.log(withKey);
// { keyboard: 75 }

Object Transformation

javascript
let grades = {
  Alice: 85,
  Bob: 92,
  Charlie: 78,
  David: 95,
};

// Convert to array format
let gradeList = Object.entries(grades).map(([name, score]) => ({
  student: name,
  grade: score,
  passed: score >= 80,
}));

console.log(gradeList);
// [
//   { student: "Alice", grade: 85, passed: true },
//   { student: "Bob", grade: 92, passed: true },
//   { student: "Charlie", grade: 78, passed: false },
//   { student: "David", grade: 95, passed: true }
// ]

Object.assign() - Merge Objects

Object.assign() copies all enumerable properties from one or more source objects to the target object.

javascript
let target = { a: 1, b: 2 };
let source = { b: 3, c: 4 };

let result = Object.assign(target, source);
console.log(result); // { a: 1, b: 3, c: 4 }
console.log(target); // { a: 1, b: 3, c: 4 } - target object is modified
console.log(target === result); // true - returns the target object

If there are identical properties, later source objects will override earlier ones. Object.assign() modifies the target object, so if you want to keep the original object unchanged, the first parameter should be an empty object:

javascript
let defaults = {
  theme: "light",
  fontSize: 14,
  language: "en",
};

let userSettings = {
  theme: "dark",
  fontSize: 16,
};

// ❌ This will modify defaults
let settings1 = Object.assign(defaults, userSettings);
console.log(defaults.theme); // "dark" - modified

// ✅ Use empty object as target
let defaults2 = {
  theme: "light",
  fontSize: 14,
  language: "en",
};

let settings2 = Object.assign({}, defaults2, userSettings);
console.log(defaults2.theme); // "light" - unchanged
console.log(settings2); // { theme: "dark", fontSize: 16, language: "en" }

Merging Multiple Objects

javascript
let base = { x: 1 };
let extra1 = { y: 2 };
let extra2 = { z: 3 };

let combined = Object.assign({}, base, extra1, extra2);
console.log(combined); // { x: 1, y: 2, z: 3 }

// Modern alternative: spread operator (recommended)
let combined2 = { ...base, ...extra1, ...extra2 };
console.log(combined2); // { x: 1, y: 2, z: 3 }

Real-world Application: Configuration Merging

javascript
function createConfig(userConfig) {
  let defaultConfig = {
    apiUrl: "https://api.example.com",
    timeout: 5000,
    retries: 3,
    cache: true,
    headers: {
      "Content-Type": "application/json",
    },
  };

  return Object.assign({}, defaultConfig, userConfig);
}

let config = createConfig({
  timeout: 10000,
  retries: 5,
});

console.log(config);
// {
//   apiUrl: "https://api.example.com",
//   timeout: 10000,
//   retries: 5,
//   cache: true,
//   headers: { "Content-Type": "application/json" }
// }

Object.freeze() - Freeze Objects

Object.freeze() freezes an object, making its properties unmodifiable, undeletable, and unaddable.

javascript
let config = {
  appName: "MyApp",
  version: "1.0.0",
  mode: "production",
};

Object.freeze(config);

// Try to modify - fails silently in strict mode, throws error in non-strict mode
config.mode = "development"; // Invalid
config.newProperty = "test"; // Invalid
delete config.version; // Invalid

console.log(config);
// { appName: "MyApp", version: "1.0.0", mode: "production" }

// Check if object is frozen
console.log(Object.isFrozen(config)); // true

Note that Object.freeze() is a shallow freeze; it only freezes the first level of properties:

javascript
let user = {
  name: "Alice",
  settings: {
    theme: "dark",
    notifications: true,
  },
};

Object.freeze(user);

// ❌ Cannot modify first level
user.name = "Bob"; // Invalid

// ⚠️ Can modify nested objects
user.settings.theme = "light"; // Valid!
console.log(user.settings.theme); // "light"

Deep Freezing

To completely freeze an object (including nested objects), you need to recursively freeze:

javascript
function deepFreeze(obj) {
  // Get all property names
  Object.getOwnPropertyNames(obj).forEach((prop) => {
    let value = obj[prop];

    // If property value is an object and not frozen, recursively freeze
    if (value && typeof value === "object" && !Object.isFrozen(value)) {
      deepFreeze(value);
    }
  });

  return Object.freeze(obj);
}

let appConfig = {
  api: {
    baseUrl: "https://api.example.com",
    endpoints: {
      users: "/users",
      posts: "/posts",
    },
  },
  features: {
    darkMode: true,
    notifications: false,
  },
};

deepFreeze(appConfig);

// Now all levels are frozen
appConfig.api.endpoints.users = "/v2/users"; // Invalid
console.log(appConfig.api.endpoints.users); // "/users"

Object.seal() - Seal Objects

Object.seal() seals an object, preventing the addition of new properties and deletion of existing properties, but allowing modification of existing property values.

javascript
let product = {
  name: "Laptop",
  price: 999,
  inStock: true,
};

Object.seal(product);

// ✅ Can modify existing properties
product.price = 899;
console.log(product.price); // 899

// ❌ Cannot add new properties
product.warranty = "2 years"; // Invalid

// ❌ Cannot delete properties
delete product.inStock; // Invalid

console.log(product);
// { name: "Laptop", price: 899, inStock: true }

// Check if object is sealed
console.log(Object.isSealed(product)); // true

freeze vs seal Comparison

javascript
let frozenObj = Object.freeze({ x: 1 });
let sealedObj = Object.seal({ x: 1 });

// freeze: cannot modify values
frozenObj.x = 2;
console.log(frozenObj.x); // 1 - unchanged

// seal: can modify values
sealedObj.x = 2;
console.log(sealedObj.x); // 2 - changed

// Both cannot add new properties
frozenObj.y = 3; // Invalid
sealedObj.y = 3; // Invalid

console.log(Object.isFrozen(frozenObj)); // true
console.log(Object.isSealed(sealedObj)); // true
console.log(Object.isSealed(frozenObj)); // true - frozen objects are also sealed
console.log(Object.isFrozen(sealedObj)); // false - sealed objects are not frozen

Object.fromEntries() - Create Objects from Key-Value Pairs

Object.fromEntries() is the inverse operation of Object.entries(), creating objects from arrays of key-value pairs.

javascript
let entries = [
  ["name", "Charlie"],
  ["age", 28],
  ["city", "London"],
];

let person = Object.fromEntries(entries);
console.log(person);
// { name: "Charlie", age: 28, city: "London" }

Real-world Application: URL Parameter Parsing

javascript
function parseQueryString(queryString) {
  let params = new URLSearchParams(queryString);
  return Object.fromEntries(params);
}

let url = "?name=Alice&age=25&city=New+York";
let parsed = parseQueryString(url);
console.log(parsed);
// { name: "Alice", age: "25", city: "New York" }

Map to Object

javascript
let userMap = new Map([
  ["id", 123],
  ["username", "alice"],
  ["email", "[email protected]"],
]);

let userObj = Object.fromEntries(userMap);
console.log(userObj);
// { id: 123, username: "alice", email: "[email protected]" }

Object Transformation and Filtering

javascript
let prices = {
  laptop: 999,
  mouse: 25,
  keyboard: 75,
  monitor: 299,
};

// Apply 10% discount to all prices
let discounted = Object.fromEntries(
  Object.entries(prices).map(([item, price]) => [item, price * 0.9])
);

console.log(discounted);
// { laptop: 899.1, mouse: 22.5, keyboard: 67.5, monitor: 269.1 }

// Round prices down
let rounded = Object.fromEntries(
  Object.entries(discounted).map(([item, price]) => [item, Math.floor(price)])
);

console.log(rounded);
// { laptop: 899, mouse: 22, keyboard: 67, monitor: 269 }

Object.create() - Create Objects with Specified Prototype

Object.create() creates a new object, using the specified object as the prototype for the new object.

javascript
let animalPrototype = {
  eat() {
    return `${this.name} is eating`;
  },
  sleep() {
    return `${this.name} is sleeping`;
  },
};

let cat = Object.create(animalPrototype);
cat.name = "Whiskers";
cat.sound = "Meow";

console.log(cat.eat()); // "Whiskers is eating"
console.log(cat.sleep()); // "Whiskers is sleeping"
console.log(cat.sound); // "Meow"

let dog = Object.create(animalPrototype);
dog.name = "Buddy";
dog.sound = "Woof";

console.log(dog.eat()); // "Buddy is eating"

Creating Pure Objects

Normal objects inherit from Object.prototype. Sometimes we need a completely pure object:

javascript
// Normal objects inherit many methods
let normalObj = {};
console.log(normalObj.toString); // function toString() { [native code] }
console.log(normalObj.hasOwnProperty); // function hasOwnProperty() { [native code] }

// Pure objects have no inherited properties
let pureObj = Object.create(null);
console.log(pureObj.toString); // undefined
console.log(pureObj.hasOwnProperty); // undefined

// Pure objects are suitable as pure data dictionaries
pureObj.key1 = "value1";
pureObj.key2 = "value2";

Other Useful Methods

Object.hasOwn() - Check Own Properties

New method introduced in ES2022, a safer alternative to hasOwnProperty:

javascript
let obj = {
  name: "Alice",
  age: 25,
};

// Traditional way
console.log(obj.hasOwnProperty("name")); // true

// New way (recommended)
console.log(Object.hasOwn(obj, "name")); // true
console.log(Object.hasOwn(obj, "toString")); // false

// Safer for objects created with Object.create(null)
let pureObj = Object.create(null);
pureObj.key = "value";

// ❌ hasOwnProperty doesn't exist
// pureObj.hasOwnProperty("key"); // TypeError

// ✅ Object.hasOwn works normally
console.log(Object.hasOwn(pureObj, "key")); // true

Object.getOwnPropertyNames() - Get All Property Names

Returns all own property names of an object, including non-enumerable ones:

javascript
let obj = {
  visible: 1,
};

Object.defineProperty(obj, "hidden", {
  value: 2,
  enumerable: false,
});

console.log(Object.keys(obj)); // ["visible"]
console.log(Object.getOwnPropertyNames(obj)); // ["visible", "hidden"]

Real-world Case Study: Object Utility Library

javascript
const ObjectUtils = {
  // Deep clone object
  deepClone(obj) {
    if (obj === null || typeof obj !== "object") return obj;
    if (obj instanceof Date) return new Date(obj);
    if (obj instanceof Array) return obj.map((item) => this.deepClone(item));

    const cloned = {};
    for (let key in obj) {
      if (Object.hasOwn(obj, key)) {
        cloned[key] = this.deepClone(obj[key]);
      }
    }
    return cloned;
  },

  // Deep merge objects
  deepMerge(target, ...sources) {
    if (!sources.length) return target;

    const source = sources.shift();

    if (this.isObject(target) && this.isObject(source)) {
      for (let key in source) {
        if (Object.hasOwn(source, key)) {
          if (this.isObject(source[key])) {
            if (!target[key]) target[key] = {};
            this.deepMerge(target[key], source[key]);
          } else {
            target[key] = source[key];
          }
        }
      }
    }

    return this.deepMerge(target, ...sources);
  },

  // Check if it's an object
  isObject(item) {
    return item && typeof item === "object" && !Array.isArray(item);
  },

  // Get nested property
  getNestedValue(obj, path) {
    return path.split(".").reduce((current, key) => current?.[key], obj);
  },

  // Set nested property
  setNestedValue(obj, path, value) {
    let keys = path.split(".");
    let lastKey = keys.pop();
    let target = keys.reduce((current, key) => {
      if (!(key in current)) current[key] = {};
      return current[key];
    }, obj);
    target[lastKey] = value;
  },

  // Remove empty value properties
  removeEmpty(obj) {
    return Object.fromEntries(
      Object.entries(obj).filter(([_, value]) => {
        if (value === null || value === undefined || value === "") {
          return false;
        }
        if (this.isObject(value)) {
          return Object.keys(this.removeEmpty(value)).length > 0;
        }
        return true;
      })
    );
  },

  // Compare if two objects are equal
  isEqual(obj1, obj2) {
    if (obj1 === obj2) return true;
    if (
      !this.isObject(obj1) ||
      !this.isObject(obj2) ||
      obj1 === null ||
      obj2 === null
    ) {
      return false;
    }

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

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

    return keys1.every((key) => {
      let val1 = obj1[key];
      let val2 = obj2[key];

      if (this.isObject(val1) && this.isObject(val2)) {
        return this.isEqual(val1, val2);
      }

      return val1 === val2;
    });
  },
};

// Usage examples
let original = {
  user: {
    name: "Alice",
    settings: { theme: "dark" },
  },
};

let cloned = ObjectUtils.deepClone(original);
cloned.user.settings.theme = "light";
console.log(original.user.settings.theme); // "dark" - unaffected

let base = { a: 1, nested: { x: 1 } };
let override = { b: 2, nested: { y: 2 } };
let merged = ObjectUtils.deepMerge({}, base, override);
console.log(merged); // { a: 1, b: 2, nested: { x: 1, y: 2 } }

let data = { user: { profile: { name: "Bob" } } };
console.log(ObjectUtils.getNestedValue(data, "user.profile.name")); // "Bob"

let dirty = { name: "Alice", email: "", age: null, city: "NYC" };
console.log(ObjectUtils.removeEmpty(dirty)); // { name: "Alice", city: "NYC" }

Common Pitfalls and Best Practices

1. Object.assign is Shallow Copy

javascript
let original = {
  name: "Alice",
  settings: { theme: "dark" },
};

let copy = Object.assign({}, original);
copy.settings.theme = "light";

console.log(original.settings.theme); // "light" - modified!

// ✅ Use other methods for deep copy
let deepCopy = JSON.parse(JSON.stringify(original));

2. Object.freeze is Shallow

javascript
let config = Object.freeze({
  api: { url: "https://api.com" },
});

// ❌ Nested objects can still be modified
config.api.url = "https://new-api.com";
console.log(config.api.url); // "https://new-api.com"

3. Pay Attention to Method Return Values

javascript
let obj1 = { a: 1 };
let obj2 = { b: 2 };

// Object.assign returns the target object (first parameter)
let result = Object.assign(obj1, obj2);
console.log(result === obj1); // true - obj1 is modified and returned

// Object.freeze/seal also return the passed object
let frozen = Object.freeze(obj1);
console.log(frozen === obj1); // true

Summary

JavaScript object methods provide us with a powerful toolkit:

  • Object.keys/values/entries() - Extract keys, values, or key-value pairs from objects
  • Object.assign() - Merge objects (shallow copy)
  • Object.freeze() - Completely freeze objects, making them unmodifiable
  • Object.seal() - Seal objects, allowing modification but preventing addition/deletion of properties
  • Object.fromEntries() - Create objects from key-value pair arrays
  • Object.create() - Create objects with specified prototype
  • Object.hasOwn() - Safely check own properties

Mastering these methods helps you:

  • Efficiently traverse and transform object data
  • Safely merge and clone objects
  • Control object mutability
  • Implement complex data operations and validation

These methods are fundamental tools for modern JavaScript development. Proficient use of them will greatly improve your code quality and development efficiency.