Lesson 42: Mastering JavaScript Object.keys, Object.values, and Object.entries with challenges!

manoj ymkmanoj ymk
5 min read

What Are These Methods?

They allow you to extract keys, values, or key-value pairs from plain JavaScript objects (not arrays, not maps):

const user = { name: "Alice", age: 25 };

Object.keys(user);   // ["name", "age"]
Object.values(user); // ["Alice", 25]
Object.entries(user);// [["name", "Alice"], ["age", 25]]

Key Characteristics:

MethodReturn TypeIterates OverNotes
Object.keys(obj)string[]enumerable keysReturns only own (non-inherited) enumerable keys
Object.values(obj)any[]enumerable valuesSame as above
Object.entries(obj)[string, any][]key-value pairsGreat for transformation pipelines

Visualization:

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

Object.entries(obj) ➝
[
  ["a", 1],
  ["b", 2]
]

🔹 2. Fill Any Gaps

🔸 Symbols Are Ignored

const sym = Symbol("hidden");
const obj = { a: 1, [sym]: 42 };

Object.keys(obj);         // ["a"]
Object.getOwnPropertySymbols(obj); // [Symbol(hidden)]
Reflect.ownKeys(obj);     // ["a", Symbol(hidden)]

🔸 Order of Keys

  • Numeric-like keys come first, sorted as numbers.

  • Then string keys in insertion order.

  • Then symbol keys (not included in Object.keys/values/entries).

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

🔸 Only "own" and enumerable keys

const proto = { inherited: 1 };
const obj = Object.create(proto);
obj.own = 2;

Object.keys(obj); // ["own"]

🔸 Not directly on the object

const obj = { a: 1 };
// obj.keys() ❌ → TypeError
Object.keys(obj); // ✅

🔹 3. Challenge Me Deeply

🟢 Basic

  1. Create an object and use Object.keys, Object.values, and Object.entries to log its structure.

  2. Write a function sumValues(obj) that returns the sum of all numeric values in an object.

  3. Use for..of and Object.entries to print key-value pairs with a dash separator (key - value).

🟡 Intermediate

  1. Write a function that filters out all key-value pairs where the value is falsy (e.g., 0, null, undefined, false, "").

  2. Implement an invertObject(obj) function that swaps keys and values.

  3. Write a deepLog(obj) that logs each key and its value's type using Object.entries.

  4. Given a prices object, return a new object with a 10% discount applied to each price.

🔴 Advanced

  1. Write a function that deeply clones an object only using Object.entries (no structuredClone or JSON.parse).

  2. Create a serialize(obj) function that flattens nested objects into a key path representation:

     // Input: { a: 1, b: { c: 2 } }
     // Output: { "a": 1, "b.c": 2 }
    
  3. Write a function renameKeys(obj, renameMap) that takes an object and a mapping of old keys to new ones and returns a new object with renamed keys.

🎯 Brain-Twister

  1. Why doesn’t the following work as expected?
const obj = { 1: "a", 2: "b" };
console.log(Object.keys(obj)); // ?
console.log(Object.entries(obj)[0][0] === 1); // true or false?

🔹 4. Interview-Ready Questions

🔍 Conceptual

  • What’s the difference between for...in and Object.keys()?

  • Why doesn’t Object.keys return symbol keys?

  • How is the key order determined in Object.keys()?

⚠️ Debugging / Tricky

  • You're using Object.entries(obj) and modifying the array it returns. Will that affect the original object?

  • Someone wrote obj.keys(). Why doesn’t it work? How would you fix it?

  • You use Object.keys(obj).map(...) on a prototype-based object and it returns fewer keys than expected. Why?

💼 Real-World Interview Simulation

You’re given an object of configuration settings from a legacy API. Write code that:

  • Removes any null or undefined values

  • Converts all keys to camelCase (assume helper provided)

  • Returns a new cleaned object

✅ Best Practices

  • ✅ Use Object.entries().map().fromEntries() for object transformations.

  • ✅ Avoid mutating objects during iteration.

  • ✅ Prefer Reflect.ownKeys() when symbols matter.

❌ Red Flags

  • ❌ Using for...in without hasOwnProperty guard.

  • ❌ Relying on key order without understanding it.

  • ❌ Using obj.keys() instead of Object.keys(obj).


🔹 5. Real-World Usage

🔧 In Frameworks & Libraries

  • React: Dynamic prop mapping or form handling

  • Express: Cleaning or transforming req.query or req.body

  • Lodash: Utilities like _.mapValues, _.invert wrap around similar patterns

  • MongoDB Aggregation: Often transformed to/from key-value pairs for computation

🧪 Testing

Use Object.entries(obj).every(([key, val]) => typeof val === 'string') to assert value types.


🔹 6. Remember Like a Pro

🧠 Mnemonic:

KVE = Keys, Values, Entries — Think:

  • K = list of property Keys

  • V = list of property Values

  • E = Everything (keys and values)

🔁 Mind Map:

                 +----------------+
                 | Plain Objects  |
                 +----------------+
                     |
        +------------+-------------+
        |            |             |
  Object.keys   Object.values   Object.entries
    (keys)         (values)       (pairs)

🧾 Cheatsheet:

Object.keys(obj)         // [key1, key2, ...]
Object.values(obj)       // [value1, value2, ...]
Object.entries(obj)      // [[key1, value1], [key2, value2], ...]

Object.fromEntries([[key, val]]) // → Recreate object
Reflect.ownKeys(obj)     // Includes Symbol keys
Object.getOwnPropertySymbols(obj) // Only symbols

🔹 7. Apply It in a Fun Way

🛠 Mini Project: “Budget Transformer”

Goal: Input a nested object of categories and prices, output a cleaned and flattened object with transformed values.

Steps:

  1. Take a nested object like:

     {
       food: { banana: 1, meat: 5 },
       drinks: { water: 1, soda: 2 }
     }
    
  2. Flatten it to:

     {
       "food.banana": 1,
       "food.meat": 5,
       "drinks.water": 1,
       "drinks.soda": 2
     }
    
  3. Multiply each price by 1.15 for tax

  4. Use Object.entries, map, and Object.fromEntries to achieve this.

Bonus Extension:

  • Add ability to exclude zero or negative values.

  • Support deeper nesting with recursion.


➕ Bonus Insights

🔍 Common Mistakes:

  • Assuming order of Object.keys() is always insertion order (not true with numeric keys).

  • Using Object.keys() to iterate over arrays — prefer array.forEach.

⚡ Performance Tips:

  • Object.keys() is faster than for...in due to no prototype chain traversal.

  • Avoid repeatedly calling Object.entries() in a loop.

📦 Used Heavily In:

  • JSON manipulation

  • Config builders

  • React props mapping

  • Form validation logic

0
Subscribe to my newsletter

Read articles from manoj ymk directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

manoj ymk
manoj ymk