JavaScript: Advanced ES6+ Features
Explore modules, Symbols, generators, Maps, Sets, Proxy, and the modern operators that power today's JavaScript ecosystem.
Modules: export and import
ES modules let you split code across files. Each file is its own scope, you explicitly export what you want to share and import what you need.
ES Modules
Modules replace global scripts each file has its own isolated scope by default.
- Named export:
export const fn = ...imported with the exact name - Default export:
export default fnone per file, imported with any name - Namespace import:
import * as math from "./math.js" - Modules are always in strict mode and run deferred after HTML parsing
Named and Default Exports
Export individual values by name or a single default, import both in one statement.
Press Run to execute the code and see output here.
Dynamic Imports
import() loads a module on demand at runtime and returns a Promise, enabling code splitting and lazy loading.
Dynamic import()
Dynamic imports let you load heavy features only when the user actually needs them.
- Returns a Promise resolving to the module namespace object
- The path can be a variable or expression unlike static imports
- Supported by all modern bundlers (Vite, Webpack) for automatic code splitting
- Works in both ES modules and classic scripts
Dynamic import()
Defer loading heavy modules until they are actually needed at runtime.
Press Run to execute the code and see output here.
Symbols
A Symbol is a primitive value that is always unique. No two Symbols are ever equal, making them ideal as property keys that never clash with any other code.
Symbol
Symbols are the only primitive type guaranteed to be unique on every creation.
- Create with
Symbol("description"), the description is for debugging only - Symbol keys are hidden from
for...in,Object.keys(), andJSON.stringify() Symbol.for("key")creates a global shared symbol, same key returns the same Symbol- Built-in well-known Symbols:
Symbol.iterator,Symbol.toPrimitive
Symbols as Unique Keys
Symbol keys are unique and invisible to standard enumeration.
Press Run to execute the code and see output here.
Iterators and the Iterable Protocol
An iterable is any object with a [Symbol.iterator] method that returns an iterator. An iterator has a next() method returning { value, done }.
Iterable Protocol
Any object that implements Symbol.iterator works with for...of, spread, and destructuring.
- Arrays, strings, Maps, Sets, and generators are built-in iterables
- Custom iterables let you define how your object is traversed
- Iterator returns
{ value, done: false }per step and{ value: undefined, done: true }at end
Custom Iterable
Implement Symbol.iterator to make any object work with for...of and spread.
Press Run to execute the code and see output here.
Generator Functions
A generator function (function*) can pause with yield and resume later, producing values lazily on demand.
Generator Functions
Generators produce values on demand useful for infinite sequences, lazy evaluation, and async flows.
- Calling a generator function returns an iterator the body does not run immediately
yieldpauses the function and returns a value to the caller- The next
.next()call resumes from where it paused - Generators are automatically iterable use them with
for...of
Generator Functions
Pause with yield, resume with next(), create lazy sequences including infinite ones.
Press Run to execute the code and see output here.
Map
A Map is a key-value collection that accepts any value as a key, preserves insertion order, and has a cleaner API than a plain object.
Map
Use Map when keys are not strings, when insertion order matters, or when you frequently add and remove keys.
map.set(key, value),map.get(key),map.has(key),map.delete(key)map.sizegives the count instantly- Iterable: loop with
for...ofovermap.entries(),map.keys(),map.values() - Keys are compared by identity (
===), objects and functions can be keys
Map
Key-value pairs with any key type, guaranteed insertion order, and clean iteration.
Press Run to execute the code and see output here.
Set
A Set is a collection of unique values. Duplicates are silently ignored, making it the simplest way to deduplicate an array.
Set
Use Set when uniqueness matters: deduplication, membership checks, set operations.
set.add(value),set.has(value),set.delete(value),set.size- Deduplicate an array:
[...new Set(array)] - Iterable: use
for...ofdirectly in insertion order - Values compared by identity, two different objects are always unique entries
Set
Unique collections, easy deduplication, and clean set operations.
Press Run to execute the code and see output here.
WeakMap and WeakSet
Weak variants hold references to objects without preventing garbage collection. When an object is no longer referenced elsewhere, its entry is automatically removed.
WeakMap and WeakSet
Use weak collections to attach metadata to objects without causing memory leaks.
- WeakMap: keys must be objects entries are removed when the key is GC'd
- WeakSet: values must be objects removed when the object is GC'd
- Neither is iterable no
size, noforEach, nokeys() - Common use: caching DOM node metadata, storing private state per instance
WeakMap for Private Metadata
Attach data to objects without preventing them from being garbage-collected.
Press Run to execute the code and see output here.
Proxy and Reflect
Proxy wraps an object and intercepts operations on it. Reflect provides default implementations for those same operations.
Proxy and Reflect
Proxy powers Vue 3's reactivity system, validation libraries, and observable patterns.
new Proxy(target, handler)handler defines traps:get,set,deleteProperty- Call
Reflect.set(target, key, value)inside a trap to perform the default behaviour - Common uses: input validation on assignment, change tracking, logging
- The proxy is transparent to the outside callers do not know they are using a proxy
Proxy with Validation
Intercept property writes to enforce rules before storing the value.
Press Run to execute the code and see output here.
Optional Chaining (?.)
The optional chaining operator short-circuits to undefined instead of throwing when a property in the chain is null or undefined.
Optional Chaining (?.)
Replace deep null-checks with ?. for safe property access on possibly-missing values.
- Property access:
user?.address?.city - Method call:
user?.getProfile?.() - Array index:
arr?.[0] - Combine with
??to provide a fallback:user?.age ?? "unknown"
Optional Chaining
Access deeply nested properties safely, undefined instead of a TypeError.
Press Run to execute the code and see output here.
Nullish Coalescing (??)
The nullish coalescing operator returns the right-hand side only when the left-hand side is null or undefinedunlike || which also triggers on0, "", and false.
Nullish Coalescing (??)
Use ?? for default values when 0, false, or empty string are valid and should not be replaced.
a ?? b: returnsbonly ifaisnullorundefineda || b: returnsbfor any falsyaincluding 0, "", false- Nullish assignment:
user.role ??= "guest"assigns only if currently null/undefined - Combine with
?.:user?.score ?? 0
?? vs ||
?? preserves intentional falsy values like 0 and '' || replaces all of them.
Press Run to execute the code and see output here.
Knowledge Check
1. What is the difference between a named export and a default export?
2. What makes a Symbol unique?
3. What does a generator function return when called?
4. What is the key difference between Map and a plain object?
5. What does optional chaining (?.) return when a property in the chain is null or undefined?
6. When does the nullish coalescing operator (??) use the right-hand side value?
7. What is a WeakMap different from a regular Map?