Detailed Research Notes on JavaScript
ES6+ Features
This document provides detailed research notes on key features introduced in ECMAScript
2015 (ES6) and subsequent versions (ES7, ES8, ES9, etc.), often collectively referred to as
ES6+. These features have significantly enhanced JavaScript's capabilities, readability, and
developer experience.
1. let and const Declarations
ES6 introduced let and const as alternatives to var for variable declaration, providing
block-scoping and improved control over variable immutability.
● let: Declares a block-scoped local variable, optionally initializing it to a value. It can be
reassigned.
● const: Declares a block-scoped, read-only named constant. It must be initialized at
declaration and cannot be reassigned.
// Using let
let count = 10;
if (true) {
let count = 20; // Different 'count' variable, block-scoped
[Link](count); // Output: 20
}
[Link](count); // Output: 10
// Using const
const PI = 3.14159;
// PI = 3.14; // This would cause an error: Assignment to constant
variable.
const user = { name: 'Alice' };
[Link] = 'Bob'; // This is allowed: modifying properties of a const
object
[Link](user); // Output: { name: 'Bob' }
// user = { name: 'Charlie' }; // This would cause an error:
Reassignment of const variable
2. Arrow Functions (=>)
Arrow functions provide a more concise syntax for writing function expressions. They also have
a lexical this binding, meaning this is determined by the surrounding scope, not by how the
function is called.
// Traditional function expression
const addTraditional = function(a, b) {
return a + b;
};
[Link](addTraditional(2, 3)); // Output: 5
// Arrow function (concise syntax for single expression)
const addArrow = (a, b) => a + b;
[Link](addArrow(2, 3)); // Output: 5
// Arrow function with block body
const greet = (name) => {
const greeting = `Hello, ${name}!`;
return greeting;
};
[Link](greet('World')); // Output: Hello, World!
// Lexical 'this' example
function Timer() {
[Link] = 0;
setInterval(() => {
[Link]++; // 'this' refers to the Timer instance
[Link]([Link]);
}, 1000);
}
// const timer = new Timer(); // Uncomment to see it in action
3. Template Literals (Template Strings)
Template literals allow for easier string interpolation and multiline strings using backticks (`).
const name = 'Alice';
const age = 30;
// Traditional string concatenation
const messageOld = 'Hello, my name is ' + name + ' and I am ' + age +
' years old.';
[Link](messageOld);
// Using template literals
const messageNew = `Hello, my name is ${name} and I am ${age} years
old.`;
[Link](messageNew);
// Multiline strings
const multilineString = `
This is a string
that spans multiple
lines.
`;
[Link](multilineString);
4. Destructuring Assignment
Destructuring assignment allows you to unpack values from arrays or properties from objects
into distinct variables.
Array Destructuring
const colors = ['red', 'green', 'blue'];
// Destructuring array elements
const [firstColor, secondColor, thirdColor] = colors;
[Link](firstColor); // Output: red
[Link](secondColor); // Output: green
// Skipping elements
const [,, lastColor] = colors;
[Link](lastColor); // Output: blue
// Swapping variables easily
let a = 1;
let b = 2;
[a, b] = [b, a];
[Link](a, b); // Output: 2 1
Object Destructuring
const person = {
firstName: 'John',
lastName: 'Doe',
age: 40
};
// Destructuring object properties
const { firstName, age } = person;
[Link](firstName); // Output: John
[Link](age); // Output: 40
// Renaming properties during destructuring
const { firstName: fName, lastName: lName } = person;
[Link](fName); // Output: John
[Link](lName); // Output: Doe
// Destructuring with default values
const { city = 'New York', age: personAge } = person;
[Link](city); // Output: New York (since 'city' not in
person)
[Link](personAge); // Output: 40
5. Spread (...) and Rest (...) Operators
The ... syntax serves two distinct purposes:
● Spread Operator: Expands an iterable (like an array or string) into individual elements.
Useful for array literals, function calls, and object literals.
● Rest Parameters: Collects an indefinite number of arguments into an array. Used in
function parameter lists.
Spread Operator Examples
// Spreading arrays
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; // Creates a new array [1, 2, 3, 4, 5]
[Link](arr2);
// Spreading objects (ES8)
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 }; // Creates a new object { a: 1, b: 2,
c: 3 }
[Link](obj2);
// Passing array elements as function arguments
const numbers = [10, 20, 30];
function sum(x, y, z) {
return x + y + z;
}
[Link](sum(...numbers)); // Output: 60
Rest Parameters Example
function collectArgs(firstArg, ...restOfArgs) {
[Link]('First argument:', firstArg);
[Link]('Rest of arguments:', restOfArgs); // restOfArgs is an
array
}
collectArgs(1, 2, 3, 4, 5);
// Output:
// First argument: 1
// Rest of arguments: [2, 3, 4, 5]
collectArgs('hello');
// Output:
// First argument: hello
// Rest of arguments: []
6. Classes
ES6 introduced class syntax, which is syntactic sugar over JavaScript's existing
prototype-based inheritance. It provides a cleaner and more familiar way to create objects and
handle inheritance.
class Animal {
constructor(name) {
[Link] = name;
}
speak() {
[Link](`${[Link]} makes a sound.`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // Call the parent constructor
[Link] = breed;
}
speak() {
[Link](`${[Link]} barks!`);
}
fetch() {
[Link](`${[Link]} fetches the ball.`);
}
}
const myAnimal = new Animal('Generic Animal');
[Link](); // Output: Generic Animal makes a sound.
const myDog = new Dog('Buddy', 'Golden Retriever');
[Link](); // Output: Buddy barks! (overridden method)
[Link](); // Output: Buddy fetches the ball.
7. Modules (import / export)
ES6 introduced a standardized module system, allowing developers to break down code into
reusable units and manage dependencies.
[Link] (Module to export)
// [Link]
export const PI = 3.14159;
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
// Default export
export default function multiply(a, b) {
return a * b;
}
[Link] (Module to import)
// [Link]
// Import named exports
import { PI, add } from './[Link]';
// Import all named exports as an object
import * as MathUtils from './[Link]';
// Import default export (can be named anything)
import multiplyNumbers from './[Link]';
[Link](PI); // Output: 3.14159
[Link](add(5, 3)); // Output: 8
[Link]([Link](10, 4)); // Output: 6
[Link](multiplyNumbers(2, 6)); // Output: 12
Note: Module import/export requires a build step (like Webpack or Parcel) or a browser that
supports ES Modules (using <script type="module">).
8. Promises
Promises provide a cleaner way to handle asynchronous operations, avoiding "callback hell." A
Promise represents the eventual completion (or failure) of an asynchronous operation and its
resulting value.
function fetchData() {
return new Promise((resolve, reject) => {
// Simulate an asynchronous operation (e.g., fetching data
from an API)
setTimeout(() => {
const success = true; // Change to false to simulate an
error
if (success) {
resolve('Data successfully fetched!');
} else {
reject('Error fetching data.');
}
}, 2000); // 2-second delay
});
}
fetchData()
.then((data) => {
[Link]('Success:', data);
return 'Processed: ' + data; // Chain another .then
})
.then((processedData) => {
[Link]('Second then:', processedData);
})
.catch((error) => {
[Link]('Error:', error);
})
.finally(() => {
[Link]('Operation finished (resolved or rejected).');
});
[Link]('Fetching data...'); // This will log immediately
9. Async/Await (ES2017 - ES8)
async and await are syntactic sugar built on top of Promises, making asynchronous code look
and behave more like synchronous code, greatly improving readability.
● async function: A function declared with async keyword automatically returns a Promise.
● await expression: Can only be used inside an async function. It pauses the execution of
the async function until the Promise it's waiting for settles (resolves or rejects).
function resolveAfter2Seconds() {
return new Promise(resolve => {
setTimeout(() => {
resolve('Resolved after 2 seconds');
}, 2000);
});
}
async function asyncCall() {
[Link]('Calling...');
const result = await resolveAfter2Seconds(); // Pause here until
Promise resolves
[Link](result); // Output: Resolved after 2 seconds
// Further synchronous-looking code executes after the await
return 'Async call complete';
}
asyncCall().then(message => [Link](message));
[Link]('This logs immediately after asyncCall is invoked.');
Error Handling with async/await
function rejectAfter1Second() {
return new Promise((_, reject) => {
setTimeout(() => {
reject('Error: Something went wrong!');
}, 1000);
});
}
async function handleAsyncError() {
try {
[Link]('Attempting to fetch...');
const data = await rejectAfter1Second();
[Link]('Data:', data); // This line will not be reached
} catch (error) {
[Link]('Caught an error:', error); // Output: Caught an
error: Error: Something went wrong!
} finally {
[Link]('Cleanup or final actions.');
}
}
handleAsyncError();
10. Default Parameters
Default parameters allow you to initialize function parameters with default values if no value or
undefined is passed.
function greetPerson(name = 'Guest', greeting = 'Hello') {
[Link](`${greeting}, ${name}!`);
}
greetPerson('Alice'); // Output: Hello, Alice!
greetPerson(); // Output: Hello, Guest!
greetPerson('Bob', 'Hi'); // Output: Hi, Bob!
greetPerson(undefined, 'Hey'); // Output: Hey, Guest!
11. Enhanced Object Literals
ES6 introduced several enhancements to object literals, making them more concise and
powerful.
● Property Shorthand: If a variable name is the same as the desired property name, you
can just list the variable.
● Method Shorthand: A more concise syntax for defining methods.
● Computed Property Names: Allows using an expression for a property name.
const userName = 'Charlie';
const userAge = 25;
const role = 'admin';
const userProfile = {
// Property Shorthand
userName,
userAge,
// Method Shorthand
greet() {
[Link](`Hello, ${[Link]}!`);
},
// Computed Property Names
[role + 'Id']: 123,
// Traditional property
isActive: true
};
[Link](userProfile);
// Output: { userName: 'Charlie', userAge: 25, adminId: 123, isActive:
true, greet: [Function: greet] }
[Link](); // Output: Hello, Charlie!
12. Iterators and Generators (Brief Overview)
● Iterators: Objects that define a sequence and a return value upon its termination. They
implement the next() method, which returns an object with value and done properties.
● Generators: Functions that can be paused and resumed, yielding (returning) multiple
values over time. They are defined using function* and use the yield keyword. They are a
powerful way to create custom iterators.
// Simple Generator Function
function* idGenerator() {
let id = 1;
while (true) {
yield id++;
}
}
const gen = idGenerator();
[Link]([Link]().value); // Output: 1
[Link]([Link]().value); // Output: 2
[Link]([Link]().value); // Output: 3
13. Map and Set
New built-in data structures for more efficient data handling.
● Map: A collection of key-value pairs where keys can be of any data type (unlike plain
objects where keys are always strings or symbols). Maintains insertion order.
const myMap = new Map();
[Link]('name', 'Alice');
[Link](1, 'number one');
[Link](true, 'boolean key');
[Link]({}, 'object key'); // Objects can be keys
[Link]([Link]('name')); // Output: Alice
[Link]([Link]); // Output: 4
[Link]([Link](1)); // Output: true
for (const [key, value] of myMap) {
[Link](`${key} = ${value}`);
}
● Set: A collection of unique values. Any duplicate values added to a Set are ignored.
Maintains insertion order.
const mySet = new Set();
[Link](1);
[Link](5);
[Link]('text');
[Link](1); // Duplicate, ignored
[Link]([Link]); // Output: 3
[Link]([Link](5)); // Output: true
[Link]([Link](10)); // Output: false
const numbersWithDuplicates = [1, 2, 2, 3, 4, 4, 5];
const uniqueNumbers = [...new Set(numbersWithDuplicates)];
[Link](uniqueNumbers); // Output: [1, 2, 3, 4, 5]