Skip to content

Object Methods: Mastering the Built-in Toolkit ​

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.