Chapter 1.7☕ 14 min read

ES6+ Modern Syntax — The New JavaScript

Purana JS bhool jao — yeh wala seedha aur saaf hai.

01Template Literals & Tagged Templates

Template literals use backticks instead of quotes. They support expression interpolation with ${ }, multiline strings without \n, and can be tagged by a function for advanced processing.

const name = 'Sai';
const city = 'Hyderabad';

// Basic interpolation
const msg = `Kem cho, ${name}! Welcome to ${city}.`;

// Expression — any JS works inside ${ }
const bill = `Total: ₹${(120 + 45 + 380).toFixed(2)}`;
const label = `Status: ${isActive ? 'Online' : 'Offline'}`;

// Multiline — no \n needed
const html = `
  <div class="card">
    <h2>${name}</h2>
    <p>${city}</p>
  </div>
`;

// Tagged template — function receives parts
function highlight(strings, ...values) {
  return strings.reduce((result, str, i) => {
    const val = values[i] ? '<mark>' + values[i] + '</mark>' : '';
    return result + str + val;
  }, '');
}
const output = highlight`Hello ${name}, you are in ${city}!`;
// "Hello <mark>Sai</mark>, you are in <mark>Hyderabad</mark>!"
Tagged templates are how libraries like GraphQL (gql`query { ... }`) and styled-components (css`color: red`) work. Angular's html` ` and css` ` in component metadata are the same concept — a tagged template that Angular processes at compile time.

String.raw is a built-in tag that prevents escape processing — useful for regex patterns and Windows paths.

02Modules — Import Export Ki Dukaan

ES Modules (ESM) are the official JavaScript module system. They enable tree-shaking, encapsulation, and eliminate global namespace pollution. Angular is built entirely on ES Modules.

// math.ts — named exports
export const PI = 3.14159;
export function add(a, b) { return a + b; }
export function multiply(a, b) { return a * b; }

// logger.ts — default export
export default class Logger {
  log(msg) { console.log(`[LOG] ${msg}`); }
}

// main.ts — importing
import Logger from './logger';               // default
import { PI, add } from './math';            // named
import { add as sum } from './math';         // renamed
import * as MathUtils from './math';         // namespace

// Barrel file — index.ts re-exports everything
export { add, multiply } from './math';
export { default as Logger } from './logger';
// Consumers import from one place:
import { add, Logger } from './utils';

// Dynamic import — lazy loading
const module = await import('./heavy-chart-library');
module.renderChart(data);
📋 Angular Tip:
Angular uses barrel files (index.ts) everywhere. When you see import { Component } from '@angular/core' — that's a barrel file re-exporting from many internal files. Create your own index.ts in each feature folder for cleaner imports.

Why modules matter: Tree-shaking (only imported code in bundle), no global pollution, explicit dependencies, static analysis for better tooling.

03Map & Set — Behtareen Data Structures

Map and Set are newer data structures that solve real problems with plain objects and arrays.

// Map — any key type, preserves insertion order
const userMap = new Map();
userMap.set('name', 'Sai');
userMap.set(42, 'answer');
userMap.set({ id: 1 }, 'object key');

console.log(userMap.size);          // 3
console.log(userMap.get('name'));   // 'Sai'
console.log(userMap.has(42));       // true

// Iterating Map
for (const [key, value] of userMap) {
  console.log(key, '->', value);
}

// Set — unique values only
const tags = new Set(['angular', 'react', 'angular', 'vue']);
console.log(tags.size);             // 3 — duplicate removed
tags.add('svelte');
tags.delete('react');
console.log(tags.has('angular'));   // true

// Deduplication pattern
const arr = [1, 2, 2, 3, 3, 3, 4];
const unique = [...new Set(arr)];   // [1, 2, 3, 4]
Angular connections: NgRx state often uses Map for entity stores — entityAdapter uses Record (object) but custom stores use Map for O(1) lookup by id. Angular CDK uses Set internally for selection tracking. WeakMap and WeakSet use object keys that are garbage-collected when the object is — useful for caching metadata without memory leaks.
04Symbols & Iterators

Symbol creates a guaranteed-unique primitive. Iterators make any object work with for...of.

// Symbol — always unique
const id = Symbol('id');
const id2 = Symbol('id');
console.log(id === id2);            // false — always unique

// As object key — never clashes with other keys
const user = {
  name: 'Sai',
  [id]: 12345,                      // symbol key — hidden from for...in
};
console.log(user[id]);              // 12345
console.log(Object.keys(user));     // ['name'] — id not included

// Well-known Symbols
// Symbol.iterator — makes objects iterable
// Symbol.toPrimitive — controls type conversion
// Symbol.hasInstance — customizes instanceof

// Custom iterable — add [Symbol.iterator]
const range = {
  from: 1,
  to: 5,
  [Symbol.iterator]() {
    let current = this.from;
    const last = this.to;
    return {
      next() {
        return current <= last
          ? { value: current++, done: false }
          : { value: undefined, done: true };
      }
    };
  }
};

for (const num of range) {
  console.log(num); // 1, 2, 3, 4, 5
}
console.log([...range]); // [1, 2, 3, 4, 5]
Why Symbol matters: Without Symbol, adding a custom key to an object could clash with a property name from another library. Symbol keys are invisible to Object.keys(), for...in, and JSON.stringify() — perfect for hidden metadata. All built-in iterables (Array, String, Map, Set) use Symbol.iterator under the hood.
05Generators & ES2024 Highlights

Generators are functions that can pause and resume. They're lazy — values produced only when asked.

// Generator — pauses at each yield
function* idGenerator() {
  let id = 1;
  while (true) {               // infinite — OK because lazy
    yield id++;
  }
}

const gen = idGenerator();
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // 3 — only computed when asked

// Finite generator
function* range(start, end, step = 1) {
  for (let i = start; i <= end; i += step) {
    yield i;
  }
}
console.log([...range(1, 10, 2)]); // [1, 3, 5, 7, 9]

// ES2024 — Object.groupBy
const items = [
  { name: 'Biryani', type: 'main' },
  { name: 'Chai',    type: 'drink' },
  { name: 'Kebab',   type: 'main' },
];
const grouped = Object.groupBy(items, item => item.type);
// { main: [...], drink: [...] }

// Promise.withResolvers — ES2024
const { promise, resolve, reject } = Promise.withResolvers();
setTimeout(() => resolve('done!'), 1000);
const result = await promise; // 'done!'
RxJS connection: RxJS Observables and generators share the same mental model — both are lazy, both push values over time, both can be infinite. If you understand generators, RxJS clicks immediately. That's why this chapter ends with generators right before Stage 2 starts TypeScript and RxJS.

Coming soon (TC39 Stage 3): Decorators (Angular already uses them via @Component, @Injectable), Temporal API for dates (replaces Date), Records and Tuples (immutable data structures).

Lo kar liya — Stage 1 Complete!

  • ✅ Template literals use backticks — ${ } for expressions, multiline, tagged templates for advanced use
  • ✅ Named exports (many per file) vs default export (one per file) — know when to use each
  • ✅ Map over Object when keys are dynamic or non-string; Set for unique collections and deduplication
  • ✅ Symbol creates a guaranteed-unique primitive — used for hidden keys and well-known protocols
  • ✅ Generators (function*) are lazy — values produced on demand; same mental model as RxJS Observables
  • ✅ ES modules enable tree-shaking — only imported code ends up in the bundle; Angular is built entirely on ESM
Course Search
Search across all chapters & stages
📖

Search the course

Type any topic — branching, stash, rebase, hooks — and jump straight to that chapter.

merge branchesgit stashundo commitrebase