Advanced JS Concepts

02 Mins

This chapter covers deeper JavaScript features that power many built-in behaviors, from iteration to memory management.

Symbols

A Symbol is a unique primitive value, often used as an object property key to avoid name collisions. Every Symbol() call creates a completely unique identifier. Even if two symbols have the same description, they are always different.

const a = Symbol("id");
const b = Symbol("id");

console.log(a === b); // false (unique!)

Symbol properties are not included in common enumeration methods like for...in or Object.keys(), but they can still be accessed using:

Object.getOwnPropertySymbols(obj);
const id = Symbol("id");

const user = {
  name: "Arjit",
  [id]: 123
};

console.log(Object.keys(user)); // ["name"]

Built-in Symbols

JavaScript defines built-in symbols (like Symbol.iterator), which customize how objects behave. This powers iteration (next section)


Custom Iterators

Iterators define how an object produces values one at a time. By implementing the Symbol.iterator method, you can make any object iterable with for…of.

for...of calls Symbol.iterator to get an iterator, then repeatedly calls .next() until { done: true } is returned.

const iterObj = {
  nums: [1, 2, 3],
  [Symbol.iterator]() {
    let i = 0;
    return {
      next: () => ({
          if (i < this.nums.length) {
            return { value: this.nums[i++], done: false };
          } else {
            return { done: true };
          }
        })
      };
    }
};

for (const n of iterObj) console.log(n);

Generators (Advanced Iterators)

Generators are special functions that can pause and resume execution, producing values one at a time. They’re useful for asynchronous flows, infinite sequences, or data pipelines.

function* counter() {
  yield 1;
  yield 2;
  yield 3;
}

for (let n of counter()) {
  console.log(n);
}

Each yield pauses execution and returns a value, resuming from the same point on the next call.


Maps and WeakMaps

  • Map: Stores key-value pairs where keys can be any type.
  • WeakMap: Similar, but keys must be objects and are held weakly (eligible for garbage collection if no other references exist).
const map = new Map();
map.set("name", "Arjit");
console.log(map.get("name")); // Arjit

const weakMap = new WeakMap();
let obj = {};
weakMap.set(obj, "data");
obj = null; // key becomes unreachable → GC can reclaim

Note - WeakMaps are often used for private data storage tied to object lifetimes.


Sets and WeakSets

  • Set: Stores unique values of any type.
  • WeakSet: Stores objects weakly, allowing garbage collection when no other references exist.
const set = new Set([1, 2, 2, 3]);
console.log(set); // Set {1, 2, 3}

const weakSet = new WeakSet();
let obj = {};
weakSet.add(obj);
obj = null; // object eligible for GC

Garbage Collection (Memory)

JavaScript uses automatic garbage collection. JavaScript engine (e.g., V8 in Chrome/Node.js) decides when memory is no longer needed and reclaims it.

Key Idea:

If a value is no longer reachable from the root (global scope or active execution contexts), it becomes eligible for garbage collection.

let obj = {a:1};
obj = null; // eligible for GC
  • Maps/Sets hold strong references → values stay in memory until explicitly removed.
  • WeakMaps/WeakSets hold weak references → values are automatically cleared when objects are unreachable.

This makes WeakMaps/WeakSets useful for memory-sensitive scenarios like caching or tracking metadata without preventing garbage collection.