Lesson 26: Mastering JavaScript Objects basics with challenges!

manoj ymkmanoj ymk
8 min read

What are JavaScript Objects?

Objects are dynamic collections of key-value pairs, where:

  • Keys (aka property names) are always strings or symbols.

  • Values can be of any type (primitives, objects, functions, etc.).

Objects are non-primitive and mutable. They're used everywhere in JS — from user-defined structures to built-in types like Array, Date, Error, etc.

let user = {
  name: "Alice",
  age: 28
};

🧱 2. Deep Internal Breakdown

Object Creation:

  • Literal syntax: let obj = { key: value };

  • Constructor: let obj = new Object();

Accessing / Modifying:

  • Dot notation: obj.key — only works for valid identifiers.

  • Bracket notation: obj["complex key"] — supports any string.

Dynamic property names (Computed):

let fruit = "apple";
let bag = {
  [fruit]: 5 // same as: bag.apple = 5
};

Shorthand:

let name = "John";
let user = { name }; // same as { name: name }

Property keys:

All keys are strings internally:

let obj = { 1: "a" };
console.log(obj["1"]); // "a"

Special property: __proto__

  • A getter/setter for the prototype.

  • Cannot be overwritten by primitives.

obj.__proto__ = 5; // silently ignored

Property Existence:

  • obj.key === undefined

  • "key" in obj ✅ (even if value is undefined)

Iteration: for..in

  • Loops over enumerable own + inherited properties

  • Key order:

    • Integer-like keys → sorted numerically.

    • Others → insertion order.

let obj = { "2": "two", "1": "one" }; // prints 1, 2

🧠 Internal Mechanics

  • Objects are internally implemented as hash tables (property-key map).

  • Property lookup time is amortized O(1) unless prototype chains grow deep.

  • Hidden classes (in V8) optimize repeated object shape usage (same properties in same order) — objects with same “shape” are faster.

💥 Commonly Missed Subtopics & Gotchas

🔸 __proto__ is not just a property

It behaves differently:

obj.__proto__ = null; // modifies prototype chain

If you want to safely add __proto__ as a normal property, use:

Object.create(null)

It creates an object with no prototype.

🔸 Property Enumeration Traps

for..in iterates enumerable inherited properties, while:

  • Object.keys() → own enumerable properties

  • Object.getOwnPropertyNames() → own properties (enumerable or not)

  • Reflect.ownKeys() → includes symbols

🔸 Numeric vs String keys

let obj = { "1": "a", 1: "b" };
console.log(obj["1"]); // b – overwrites previous value

🔸 Non-Enumerable Properties Are Invisible to for..in

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

🔸 Don’t Use Objects as Maps!

let map = {};
map["__proto__"] = "bad"; // prototype pollution!

Use Map if keys are dynamic and may collide with built-ins.

🔸 Functions are Objects too!

function greet() {}
greet.language = "English";

💻 Browser-Specific Quirks

Older IE (≤9) had issues with object enumeration order (non-standard). Modern browsers now follow spec:

  • Integer-like keys → sorted

  • Strings → insertion order

⚠️ Developers Often Get Wrong:

  • Forgetting square brackets for dynamic keys.

  • Misusing in operator vs undefined check.

  • Relying on property order from for..in or Object.keys() without realizing sorting rules.

  • Expecting objects to behave like Maps or arrays.

  • Trying to delete non-configurable properties.

⚠️ Sub-Concepts Often Missed

✅ 1. Keys are Strings or Symbols — Always

let obj = {};
obj[{}] = "val";
console.log(Object.keys(obj)); // ["[object Object]"]

All non-symbol keys are coerced to strings. Even objects. Only Symbol() avoids this.


✅ 2. Own vs Inherited Properties

for..in includes inherited enumerable props!

const parent = { a: 1 };
const child = Object.create(parent);
child.b = 2;

for (let key in child) console.log(key); // "b", then "a"

✅ 3. Non-Enumerable Props

Object.keys() skips non-enumerables:

let obj = {};
Object.defineProperty(obj, "hidden", {
  value: 123,
  enumerable: false
});
console.log(Object.keys(obj)); // []
console.log("hidden" in obj);  // true

✅ 4. Object.prototype Pollution Risk

Object.prototype.foo = 123;
let obj = {};
console.log("foo" in obj); // true — inherited

✅ Solution: Object.create(null) — a truly blank object without a prototype.


✅ 5. Reserved Keyword Safety (Object Literals)

let obj = {
  let: "valid",
  return: "also valid"
};

Works fine because property names are always strings in object literals, and reserved keywords aren’t restricted there.


✅ 6. Execution Order Trap: Integer-Like Keys Are Sorted

let obj = {
  100: "a",
  2: "b",
  7: "c"
};
console.log(Object.keys(obj)); // ["2", "7", "100"]

✅ To preserve insertion order, prefix with a character: "id_2" instead of 2.


🚨 Dev Confusions & Mistakes

MistakeWhy It’s Problematic
Using for..in on arraysIncludes inherited props + wrong order
Assigning to __proto__Alters prototype chain
Using objects for mapsMay collide with hasOwnProperty, toString
Checking key existence with obj[key] === undefinedFails when value is explicitly undefined
Using object keys to store functions or DOM nodesCan lead to memory leaks without proper cleanup

🔥 3. Challenge Me Deeply

💻 Task 1: Hello, Object

let user = {}; // Create empty object
user.name = "John"; // Add name
user.surname = "Smith"; // Add surname
user.name = "Pete"; // Modify name
delete user.name; // Remove name

💻 Task 2: isEmpty

function isEmpty(obj) {
  for (let key in obj) return false;
  return true;
}

⚠️ Object.keys(obj).length === 0 is also valid, but for..in avoids temporary array allocation.

💻 Task 3: Sum Salaries

let salaries = {
  John: 100,
  Ann: 160,
  Pete: 130
};

let sum = 0;
for (let key in salaries) {
  sum += salaries[key];
}

💻 Task 4: Multiply Numeric

function multiplyNumeric(obj) {
  for (let key in obj) {
    if (typeof obj[key] === "number") {
      obj[key] *= 2;
    }
  }
}

🎯 4. Interview-Ready Questions

✅ Basic

  1. What’s the difference between dot and bracket notation?

  2. Can object keys be non-strings?

  3. What does __proto__ do, and why is it special?

🧩 Intermediate

  1. Why might "key" in obj be better than obj.key === undefined?

  2. What is the order of keys in for..in?

  3. What happens when a number is used as a property key?

🧠 Advanced

  1. Why can’t you reliably override __proto__ with a non-object?

  2. How would you deeply clone an object?

  3. Why is it risky to use for..in with arrays?

  4. What are symbols, and why might you use them as keys?


⚠️ 5. Hidden Pitfalls & Edge Cases

PitfallExplanation
obj["key"] !== undefinedDoesn't guarantee the property exists. It could exist with undefined value.
__proto__Has special prototype-binding behavior, unlike regular keys.
Integer-like keysSorted numerically in for..in. Surprising to many!
Bracket notation in obj.keyInterprets "key" as a literal property name. Variables must be used like obj[var].
Symbol keysNot accessible via for..in, only via Object.getOwnPropertySymbols() or Reflect.ownKeys().

🛠️ 6. Practical Code Patterns

Pattern: Safe property access

if ("key" in obj) {
  // do something
}

Pattern: Clone object

let clone = { ...original }; // shallow

Pattern: Count properties

Object.keys(obj).length;

Pattern: Dynamic key assignment

let key = "age";
let obj = { [key]: 30 };

Real-World Usage

💡 In Frameworks:

  • React props/state: All objects.

  • Redux store: State trees are plain objects.

  • Vue reactivity system: Built around property access trapping.

  • Express.js: req.params, res.locals are object-based.

📦 In Libraries:

  • Lodash: _.get, _.set, _.has → all work with nested object paths.

  • MongoDB: Query filters are objects.

  • Stripe API, Firebase Config: All config-driven using object literals.

🏭 Production Examples:

  • User profile objects

  • Form schema definitions

  • Config managers

  • Service maps

  • Component registries


🔹 6. Remember Like a Pro

🔑 Mnemonic:

DOTS are simple. BRACKETS are powerful.

  • Dot: Deterministic, Definite, Defined keys

  • Only identifiers

  • Tame strings

  • Short and Sweet


🎯 Cheatsheet (Quick Visual)

FeatureDot NotationBracket Notation
Works with variable keys
Requires valid identifier
Allows spaces/symbols

🧠 Mind Map (Core Object Concepts)

                 JavaScript Object
                /       |        \
           Keys      Access      Tools
         /    \      /    \     /     \
     String  Symbol  Dot  Bracket  delete/in/for..in

🔹 7. Apply It in a Fun Way

🛠 Mini Project: Dynamic Theme Manager

Build a theme switcher where each theme is stored in an object, and properties are dynamically accessed based on user choice.


🧩 Steps:

  1. Create themes object with dark, light, and solarized keys.

  2. Store each theme's colors (bg, text, accent) as nested objects.

  3. Prompt user for theme name → use bracket notation to access theme.

  4. Apply colors to document (in browser or via simulated console log).

  5. Add fallback theme if unknown input is provided.


🧨 Bonus Extensions:

  • Allow runtime addition of new themes.

  • Use Object.keys() to list available themes.

  • Export/import theme configs via JSON.


🧠 (Optional – Extra Value)

⚙️ Open-Source Projects Using Objects Heavily:

  • ESLint configs

  • Babel plugins

  • Webpack rules/loaders

  • TailwindCSS theme configuration


🧯 Mistakes Devs Often Make

  • Modifying inherited props accidentally

  • Using delete in hot code paths (it's slow)

  • Using objects as maps without guarding key collisions


🧩 Performance Tips

  • Avoid delete → prefer obj[key] = undefined when performance-critical.

  • Use Map instead of object if keys are dynamic or non-strings.

  • For nested object access, memoize using tools like Lodash or use structured paths.

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