JS

JavaScript Fundamentals

25 lessons

Progress0%
1. Introduction to JavaScript
1What is JavaScript?2Setting Up Your Environment
2. Variables and Data Types
1Declaring Variables2Data Types3Type Conversion
3. Operators
Arithmetic OperatorsComparison OperatorsLogical Operators
4. Control Flow
Conditional StatementsLoops
5. Functions
Function Basics
6. Arrays & Iteration
Array MethodsSpread, Rest & Destructuring
7. Objects & JSON
Working with ObjectsJSON & Optional Chaining
8. OOP & Classes
Class BasicsInheritance & Private Fields
9. Modules & Modern JS
ES ModulesModern JavaScript Features
10. Async JavaScript
PromisesAsync/Await
11. Error Handling
Error Types & try/catchCustom Errors & Debugging
12. Iterators & Advanced
Iterators & GeneratorsMap, Set & WeakRefs
All Tutorials
JavaScriptModules & Modern JS
Lesson 19 of 25 min
Chapter 9 · Lesson 2

Modern JavaScript Features

Modern JavaScript Features

JavaScript evolves yearly through the TC39 process. This lesson covers several features that sharpen your daily coding: the nuances of arrow functions' this binding, template literal tricks, and new data structures like Symbol, WeakMap, and WeakSet.

Arrow Functions & this Binding

The key difference between arrow functions and regular functions is how this is resolved. Arrow functions have no own this — they capture this lexically from their surrounding scope at definition time.

Regular functions receive their own this determined at call time by how the function is invoked.

js
class Timer {
  constructor() { this.ticks = 0; }
  start() {
    // Arrow: 'this' is the Timer instance (lexical)
    setInterval(() => { this.ticks++; }, 1000);
    // Regular fn would lose 'this' here
  }
}

Template Literal Tags

Tagged templates let a function process a template literal:

js
function highlight(strings, ...values) {
  return strings.reduce((acc, str, i) =>
    acc + str + (values[i] !== undefined ? `[${values[i]}]` : ""), "");
}
const name = "Alice";
highlight`Hello ${name}!`; // "Hello [Alice]!"

Symbol

Symbols are unique, immutable primitive values. Two Symbols are never equal even if given the same description:

js
const id1 = Symbol("id");
const id2 = Symbol("id");
id1 === id2; // false

Use Symbols as unique object keys that never clash with other code's keys (e.g., library internal state).

WeakMap & WeakSet

Unlike Map and Set, WeakMap and WeakSet hold weak references — their entries do not prevent garbage collection of the key objects.

  • WeakMap: keys must be objects; useful for associating metadata with objects without preventing their GC
  • WeakSet: stores objects weakly; useful for tracking which objects have been processed

Neither is iterable — you cannot enumerate their contents.

js
const cache  = new WeakMap();
const visited = new WeakSet();

Nullish Coalescing & Optional Chaining (quick recap)

Already covered in Section 7 — these two operators (?? and ?.) fundamentally changed how JavaScript handles missing data.

Code Examples

Arrow Functions and this Bindingjavascript
class Counter {
  constructor(name) {
    this.name  = name;
    this.count = 0;
  }

  // Arrow function as class field: 'this' is always the instance
  increment = () => {
    this.count++;
    return this;
  };

  printLater() {
    // Arrow inside a method: captures 'this' from printLater's scope
    setTimeout(() => {
      console.log(`${this.name}: ${this.count}`);
    }, 0);
  }
}

const c = new Counter("MyCounter");
c.increment().increment().increment();
c.printLater();

// Contrast: detached regular method loses 'this'
const obj = {
  value: 42,
  getArrow:   () => obj.value,  // no own 'this', uses outer scope
  getRegular: function() { return this.value; },
};

const detached = obj.getRegular.bind(obj);
console.log(detached()); // 42 (re-bound)

Arrow functions defined as class fields (increment = () => {}) always keep this bound to the instance, making them safe to pass as callbacks. Regular methods need .bind() when detached from their object.

Symbol as Unique Keysjavascript
// Symbols are always unique
const sym1 = Symbol("id");
const sym2 = Symbol("id");
console.log(sym1 === sym2);   // false
console.log(typeof sym1);     // symbol

// Using Symbol as a unique object key
const ID    = Symbol("id");
const SECRET = Symbol("secret");

const user = {
  name: "Alice",
  [ID]:     12345,
  [SECRET]: "hunter2",
};

console.log(user.name);   // Alice
console.log(user[ID]);    // 12345

// Symbols are NOT enumerated by for...in or Object.keys
console.log(Object.keys(user));              // ['name']
console.log(Object.getOwnPropertySymbols(user)); // [Symbol(id), Symbol(secret)]

// Well-known symbols — customise language behaviour
class EvenNumbers {
  constructor(max) { this.max = max; }
  [Symbol.iterator]() {
    let n = 0;
    const max = this.max;
    return { next() { n += 2; return n <= max ? { value: n, done: false } : { done: true }; } };
  }
}
console.log([...new EvenNumbers(10)]);

Symbols make truly unique property keys invisible to normal enumeration. Well-known Symbols like Symbol.iterator let you integrate custom objects with built-in JavaScript protocols such as the spread operator and for...of.

WeakMap & WeakSetjavascript
// WeakMap: attach private data to objects without preventing GC
const privateData = new WeakMap();

class User {
  constructor(name, password) {
    this.name = name;
    privateData.set(this, { password });
  }

  checkPassword(attempt) {
    return privateData.get(this).password === attempt;
  }
}

const alice = new User("Alice", "s3cr3t");
console.log(alice.checkPassword("wrong"));   // false
console.log(alice.checkPassword("s3cr3t"));  // true
console.log(alice.password);                 // undefined — not on instance

// WeakSet: track visited objects
const seen = new WeakSet();

function processOnce(obj) {
  if (seen.has(obj)) {
    console.log("Already processed:", obj.id);
    return;
  }
  seen.add(obj);
  console.log("Processing:", obj.id);
}

const task = { id: "task-1" };
processOnce(task);
processOnce(task);

WeakMap stores metadata (like passwords) keyed by object reference without preventing GC when the object is no longer needed. WeakSet efficiently tracks which objects have been processed without holding strong references.

Quick Quiz

1. What is the key difference between arrow functions and regular functions regarding 'this'?

2. Are two Symbol('desc') values created separately equal to each other?

3. Why are WeakMap keys required to be objects?

Was this lesson helpful?

PreviousNext