Variables in JavaScript are containers for storing data values. var
declares variables with function scope, while let
and const
declare block-scoped variables. const
is used for constants which cannot be reassigned after declaration.
// Using var - function scoped var name = "Alice";
console.log(name); // Output: Alice
// Using let - block scoped let age = 25;
console.log(age); // Output: 25
// Using const - block scoped, cannot reassign const pi = 3.14159;
console.log(pi); // Output: 3.14159
JavaScript has dynamic typing, and common data types include string
, number
, boolean
, null
, undefined
, object
, and symbol
.
let str = "Hello";
let num = 100;
let bool = true;
let nothing = null;
let notDefined;
let obj = { key: "value" };
console.log(typeof str); // Output: string
console.log(typeof num); // Output: number
console.log(typeof bool); // Output: boolean
console.log(typeof nothing); // Output: object (this is a JavaScript quirk)
console.log(typeof notDefined); // Output: undefined
console.log(typeof obj); // Output: object
Functions can be declared with the function
keyword or assigned as expressions to variables. Function declarations are hoisted, but function expressions are not.
// Function declaration
function greet(name) {
return "Hello, " + name;
}
console.log(greet("Bob")); // Output: Hello, Bob
// Function expression
const greet2 = function(name) {
return "Hi, " + name;
};
console.log(greet2("Eve")); // Output: Hi, Eve
Arrow functions provide a shorter syntax for writing functions. They also lexically bind the this
keyword from the surrounding context.
const add = (a, b) => a + b;
console.log(add(3, 4)); // Output: 7
// Arrow function with block body
const multiply = (a, b) => {
return a * b;
};
console.log(multiply(5, 6)); // Output: 30
Template literals use backticks (`
) and allow embedded expressions using ${}
. They support multiline strings and string interpolation.
const name = "John";
const age = 30;
const greeting = `My name is ${name} and I am ${age} years old.`;
console.log(greeting);
// Multiline template literal
const multiline = `Line 1
Line 2
Line 3`;
console.log(multiline);
Destructuring allows unpacking values from arrays or properties from objects into distinct variables for cleaner and concise code.
// Array destructuring
const arr = [10, 20, 30];
const [x, y, z] = arr;
console.log(x, y, z); // Output: 10 20 30
// Object destructuring
const person = {name: "Alice", age: 25};
const {name, age} = person;
console.log(name, age); // Output: Alice 25
The spread operator (...
) expands iterable elements like arrays or objects into individual elements or properties, useful for copying and merging.
// Copy an array
const nums1 = [1, 2, 3];
const nums2 = [...nums1];
console.log(nums2); // Output: [1, 2, 3]
// Merge arrays
const arr1 = [1, 2];
const arr2 = [3, 4];
const merged = [...arr1, ...arr2];
console.log(merged); // Output: [1, 2, 3, 4]
// Copy an object
const obj1 = {a: 1, b: 2};
const obj2 = {...obj1};
console.log(obj2); // Output: {a: 1, b: 2}
Default parameters allow function parameters to have default values if no argument or undefined is passed.
function greet(name = "Guest") {
return `Hello, ${name}!`;
}
console.log(greet()); // Output: Hello, Guest!
console.log(greet("John")); // Output: Hello, John!
Rest parameters collect all remaining arguments into an array, allowing functions to accept variable numbers of arguments.
function sum(...numbers) {
return numbers.reduce((acc, curr) => acc + curr, 0);
}
console.log(sum(1, 2, 3)); // Output: 6
console.log(sum(4, 5, 6, 7)); // Output: 22
ES6 introduced classes as syntactic sugar over JavaScript's prototype-based inheritance. The constructor
method initializes new objects.
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
return `Hello, my name is ${this.name} and I am ${this.age} years old.`;
}
}
const alice = new Person("Alice", 30);
console.log(alice.greet()); // Output: Hello, my name is Alice and I am 30 years old.
Arrow functions provide a concise syntax for writing functions and lexically bind the this
value.
const add = (a, b) => a + b;
console.log(add(5, 3)); // Output: 8
Template literals allow embedding expressions inside strings using backticks `
and ${}
syntax.
const name = "Bob";
const greeting = `Hello, ${name}! Welcome.`;
console.log(greeting); // Output: Hello, Bob! Welcome.
Destructuring allows unpacking values from arrays or properties from objects into distinct variables.
// Array destructuring
const rgb = [255, 200, 0];
const [red, green, blue] = rgb;
console.log(red, green, blue); // Output: 255 200 0
// Object destructuring
const person = { name: "Eva", age: 25 };
const { name, age } = person;
console.log(name, age); // Output: Eva 25
The spread operator ...
expands arrays or objects into individual elements or properties.
// Spread with arrays
const arr1 = [1, 2];
const arr2 = [3, 4];
const combined = [...arr1, ...arr2];
console.log(combined); // Output: [1, 2, 3, 4]
// Spread with objects
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3 };
const merged = { ...obj1, ...obj2 };
console.log(merged); // Output: { a: 1, b: 2, c: 3 }
Promises represent the eventual completion (or failure) of an asynchronous operation and its resulting value.
const promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("Success!"), 1000);
});
promise.then(result => console.log(result)); // Output: Success! (after 1 second)
Async/await syntax simplifies working with promises by allowing asynchronous code to look synchronous.
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function asyncFunc() {
await wait(1000);
console.log("Waited 1 second");
}
asyncFunc(); // Output: Waited 1 second (after 1 sec)
Modules allow code to be split into separate files. You can export variables or functions and import them elsewhere.
// math.js
export function add(a, b) {
return a + b;
}
// main.js
import { add } from './math.js';
console.log(add(2, 3)); // Output: 5
Set is a collection of unique values; duplicates are automatically removed.
const set = new Set([1, 2, 3, 3, 4]);
console.log(set); // Output: Set(4) {1, 2, 3, 4}
set.add(5);
console.log(set.has(2)); // Output: true
Map is a collection of key-value pairs where keys can be any datatype.
const map = new Map();
map.set("name", "John");
map.set(1, "one");
console.log(map.get("name")); // Output: John
console.log(map.size); // Output: 2
Symbol is a unique and immutable primitive value used as a unique property key.
const sym1 = Symbol("id");
const sym2 = Symbol("id");
console.log(sym1 === sym2); // Output: false (unique symbols)
const obj = { [sym1]: "value" };
console.log(obj[sym1]); // Output: value
Template literals allow embedding expressions and multi-line strings using backticks.
const name = "Alice";
const greeting = `Hello, ${name}!`;
console.log(greeting); // Output: Hello, Alice!
const multiLine = `This is
multi-line
text.`;
console.log(multiLine); // Output: (multi-line string)
Functions can have default parameter values if no argument or undefined is passed.
function greet(name = "Guest") {
console.log(`Hello, ${name}!`);
}
greet(); // Output: Hello, Guest!
greet("Bob"); // Output: Hello, Bob!
Extract values from arrays or properties from objects into variables easily.
// Array destructuring
const arr = [1, 2, 3];
const [a, b] = arr;
console.log(a, b); // Output: 1 2
// Object destructuring
const obj = { name: "Jane", age: 30 };
const { name, age } = obj;
console.log(name, age); // Output: Jane 30
The spread operator expands iterables (arrays, strings) into individual elements.
const arr1 = [1, 2];
const arr2 = [...arr1, 3, 4];
console.log(arr2); // Output: [1, 2, 3, 4]
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 };
console.log(obj2); // Output: { a: 1, b: 2, c: 3 }
Rest parameters collect all remaining arguments into an array.
function sum(...numbers) {
return numbers.reduce((acc, num) => acc + num, 0);
}
console.log(sum(1, 2, 3)); // Output: 6
console.log(sum(4, 5, 6, 7)); // Output: 22
Arrow functions provide a concise syntax for writing functions and lexically bind 'this'.
const add = (a, b) => a + b;
console.log(add(2, 3)); // Output: 5
// With no parameters
const greet = () => console.log("Hello!");
greet(); // Output: Hello!
Promises handle asynchronous operations and provide success or failure callbacks.
const promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("Done!"), 1000);
});
promise.then(result => console.log(result)); // Output (after 1s): Done!
Async/Await allows writing asynchronous code that looks synchronous using promises.
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function run() {
console.log("Start");
await wait(1000);
console.log("End");
}
run(); // Output: Start (wait 1s) End
Classes provide syntactic sugar over prototype-based inheritance for cleaner object-oriented code.
class Person {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hi, I am ${this.name}`);
}
}
const alice = new Person("Alice");
alice.greet(); // Output: Hi, I am Alice
Modules allow splitting code into reusable files using export and import keywords.
// file: math.js
export function add(a, b) {
return a + b;
}
// file: main.js
import { add } from './math.js';
console.log(add(2, 3)); // Output: 5
Template literals allow embedding expressions and multi-line strings using backticks.
const name = "Bob";
const greeting = `Hello, ${name}!`;
console.log(greeting); // Output: Hello, Bob!
// Multi-line string
const message = `This is
multi-line
text.`;
console.log(message);
Destructuring allows unpacking values from arrays or properties from objects into variables.
// Array destructuring
const numbers = [1, 2, 3];
const [a, b, c] = numbers;
console.log(a, b, c); // Output: 1 2 3
// Object destructuring
const person = { name: "Jane", age: 25 };
const { name, age } = person;
console.log(name, age); // Output: Jane 25
Default parameters allow setting default values for function parameters if none are provided.
function greet(name = "Guest") {
console.log(`Hello, ${name}!`);
}
greet(); // Output: Hello, Guest!
greet("Alice"); // Output: Hello, Alice!
The spread operator (...) expands iterables (like arrays) into individual elements.
const arr1 = [1, 2];
const arr2 = [3, 4];
const combined = [...arr1, ...arr2];
console.log(combined); // Output: [1, 2, 3, 4]
// Spread in function call
function sum(x, y, z) {
return x + y + z;
}
const nums = [1, 2, 3];
console.log(sum(...nums)); // Output: 6
Rest parameters collect all remaining function arguments into an array.
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3)); // Output: 6
console.log(sum(4, 5, 6, 7)); // Output: 22
Maps store key-value pairs and preserve insertion order with any data type as keys.
const map = new Map();
map.set('a', 1);
map.set('b', 2);
console.log(map.get('a')); // Output: 1
console.log(map.size); // Output: 2
Sets store unique values of any type, preventing duplicates.
const set = new Set();
set.add(1);
set.add(2);
set.add(1); // duplicate ignored
console.log(set.size); // Output: 2
Symbols are unique and immutable primitive values used as object property keys.
const sym1 = Symbol('id');
const sym2 = Symbol('id');
console.log(sym1 === sym2); // Output: false
const obj = { [sym1]: 'value' };
console.log(obj[sym1]); // Output: value
Generators are functions that can pause execution and resume later, producing sequences on demand.
function* gen() {
yield 1;
yield 2;
yield 3;
}
const g = gen();
console.log(g.next().value); // Output: 1
console.log(g.next().value); // Output: 2
console.log(g.next().value); // Output: 3
Iterators provide a way to access elements of a collection sequentially.
const arr = [10, 20, 30];
const iter = arr[Symbol.iterator]();
console.log(iter.next().value); // Output: 10
console.log(iter.next().value); // Output: 20
console.log(iter.next().value); // Output: 30
Proxy objects enable custom behavior for fundamental operations (like property lookup).
const target = {};
const proxy = new Proxy(target, {
get(obj, prop) {
return prop in obj ? obj[prop] : 'default';
}
});
console.log(proxy.a); // Output: default
proxy.a = 10;
console.log(proxy.a); // Output: 10
WeakMaps hold weak references to keys, allowing garbage collection if no other references exist.
const wm = new WeakMap();
let obj = {};
wm.set(obj, "value");
console.log(wm.get(obj)); // Output: value
obj = null; // Object eligible for GC
WeakSets store weak references to objects and allow garbage collection if no other references exist.
const ws = new WeakSet();
let obj = {};
ws.add(obj);
console.log(ws.has(obj)); // Output: true
obj = null; // Object eligible for GC
JSON is a lightweight data format used for exchanging data between a server and web application. It can be easily converted between JavaScript objects and strings.
const obj = { name: "Alice", age: 25 };
const jsonString = JSON.stringify(obj);
console.log(jsonString); // Output: '{"name":"Alice","age":25}'
const parsed = JSON.parse(jsonString);
console.log(parsed.name); // Output: Alice
Use try...catch blocks to handle errors and exceptions gracefully in JavaScript without crashing the program.
try {
throw new Error('Oops!');
} catch (e) {
console.log(e.message); // Output: Oops!
}
Async/Await syntax makes working with promises simpler and code more readable by allowing asynchronous code to look synchronous.
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function asyncFunc() {
console.log('Start');
await wait(1000);
console.log('After 1 second');
}
asyncFunc();
Promises represent eventual completion (or failure) of asynchronous operations, allowing chaining and handling results or errors.
const promise = new Promise((resolve, reject) => {
setTimeout(() => resolve('Done'), 1000);
});
promise.then(result => console.log(result)); // Output after 1 sec: Done
Modules let you split JavaScript code into separate files and reuse them by exporting and importing variables or functions.
// module.js
export const name = 'Bob';
export function greet() {
console.log('Hello from module');
}
// main.js
import { name, greet } from './module.js';
console.log(name); // Output: Bob
greet(); // Output: Hello from module
Default parameters allow functions to have default values for parameters if none are provided.
function greet(name = 'Guest') {
console.log('Hello, ' + name);
}
greet(); // Output: Hello, Guest
greet('Alice'); // Output: Hello, Alice
Rest parameters allow a function to accept an indefinite number of arguments as an array.
function sum(...numbers) {
return numbers.reduce((acc, n) => acc + n, 0);
}
console.log(sum(1, 2, 3)); // Output: 6
console.log(sum(4, 5)); // Output: 9
The spread operator allows an iterable such as an array or string to be expanded in places where zero or more arguments or elements are expected.
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5];
console.log(arr2); // Output: [1, 2, 3, 4, 5]
const str = 'Hello';
const chars = [...str];
console.log(chars); // Output: ['H', 'e', 'l', 'l', 'o']
Destructuring assignment allows unpacking values from arrays or properties from objects into distinct variables.
// Array destructuring
const arr = [1, 2, 3];
const [a, b, c] = arr;
console.log(a, b, c); // Output: 1 2 3
// Object destructuring
const obj = {name: 'John', age: 30};
const {name, age} = obj;
console.log(name, age); // Output: John 30
Template literals allow embedded expressions and multi-line strings using backticks (`).
const name = 'Alice';
const greeting = `Hello, ${name}!`;
console.log(greeting); // Output: Hello, Alice!
const multiline = `Line 1
Line 2
Line 3`;
console.log(multiline);
Arrow functions provide a concise syntax for writing functions and lexically bind the this
context.
// Traditional function
function add(a, b) {
return a + b;
}
// Arrow function equivalent
const addArrow = (a, b) => a + b;
console.log(addArrow(5, 3)); // Output: 8
Functions can have default parameter values if no argument or undefined is passed.
function greet(name = 'Guest') {
return `Hello, ${name}!`;
}
console.log(greet()); // Output: Hello, Guest!
console.log(greet('Sam')); // Output: Hello, Sam!
Rest parameters collect all remaining arguments into an array.
function sum(...numbers) {
return numbers.reduce((acc, cur) => acc + cur, 0);
}
console.log(sum(1, 2, 3, 4)); // Output: 10
When property names and variable names are the same, you can use shorthand syntax.
const name = 'Bob';
const age = 25;
const person = { name, age };
console.log(person); // Output: { name: 'Bob', age: 25 }
ES6 allows method definitions and computed property names directly in object literals.
const prop = 'score';
const player = {
name: 'Amy',
[prop]: 100,
greet() {
return `Hi, I am ${this.name}`;
}
};
console.log(player.score); // Output: 100
console.log(player.greet()); // Output: Hi, I am Amy
Promises handle asynchronous operations and allow chaining of callbacks.
const promise = new Promise((resolve, reject) => {
setTimeout(() => resolve('Done!'), 1000);
});
promise.then(result => console.log(result)); // Output after 1 sec: Done!
Async/Await lets you write asynchronous code that reads like synchronous code, making it easier to understand.
async function fetchData() {
const data = await new Promise(resolve => setTimeout(() => resolve('Data loaded'), 1000));
console.log(data); // Output after 1 second: Data loaded
}
fetchData();
Classes provide a cleaner syntax to create objects and manage inheritance in JavaScript.
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
return `Hello, my name is ${this.name} and I am ${this.age} years old.`;
}
}
const john = new Person('John', 25);
console.log(john.greet()); // Output: Hello, my name is John and I am 25 years old.
Inheritance allows one class to extend another, inheriting its properties and methods.
class Animal {
constructor(name) {
this.name = name;
}
speak() {
return `${this.name} makes a noise.`;
}
}
class Dog extends Animal {
speak() {
return `${this.name} barks.`;
}
}
const dog = new Dog('Rex');
console.log(dog.speak()); // Output: Rex barks.
The spread operator (...) expands iterable objects like arrays or objects into individual elements.
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5];
console.log(arr2); // Output: [1, 2, 3, 4, 5]
const obj1 = {a: 1, b: 2};
const obj2 = {...obj1, c: 3};
console.log(obj2); // Output: {a: 1, b: 2, c: 3}
The rest operator gathers multiple arguments into an array inside a function parameter.
function multiply(multiplier, ...numbers) {
return numbers.map(n => n * multiplier);
}
console.log(multiply(2, 1, 2, 3)); // Output: [2, 4, 6]
JavaScript modules let you export and import code between files to organize projects better.
// In file math.js
export function add(a, b) {
return a + b;
}
// In file app.js
import { add } from './math.js';
console.log(add(3, 4)); // Output: 7
Optional chaining safely accesses nested object properties, returning undefined if any intermediate property is null or undefined.
const user = {
profile: {
name: 'Jane'
}
};
console.log(user?.profile?.name); // Output: Jane
console.log(user?.address?.street); // Output: undefined
The nullish coalescing operator returns the right-hand side operand when the left-hand side is null or undefined.
const foo = null ?? 'default';
console.log(foo); // Output: default
const bar = 0 ?? 42;
console.log(bar); // Output: 0
Template literals allow embedding expressions inside string literals using backticks and ${} for easier string construction.
const name = 'Alice';
const age = 30;
const message = `My name is ${name} and I am ${age} years old.`;
console.log(message); // Output: My name is Alice and I am 30 years old.
Destructuring lets you extract values from arrays or properties from objects into distinct variables with a clean syntax.
const person = { name: 'Bob', age: 40 };
const { name, age } = person;
console.log(name); // Output: Bob
console.log(age); // Output: 40
const numbers = [10, 20];
const [first, second] = numbers;
console.log(first); // Output: 10
console.log(second); // Output: 20
Arrow functions provide concise syntax for functions and lexically bind the this keyword, improving readability.
const add = (a, b) => a + b;
console.log(add(5, 3)); // Output: 8
Promises represent the eventual completion or failure of an asynchronous operation and its resulting value.
const promise = new Promise((resolve, reject) => {
setTimeout(() => resolve('Success!'), 1000);
});
promise.then(result => console.log(result)); // Output after 1 sec: Success!
Generators are functions that can pause execution and resume later, producing multiple values over time.
function* generator() {
yield 1;
yield 2;
yield 3;
}
const gen = generator();
console.log(gen.next().value); // Output: 1
console.log(gen.next().value); // Output: 2
console.log(gen.next().value); // Output: 3
Set stores unique values and Map stores key-value pairs with any types of keys.
const set = new Set([1, 2, 2, 3]);
console.log(set); // Output: Set(3) {1, 2, 3}
const map = new Map();
map.set('a', 1);
map.set('b', 2);
console.log(map.get('a')); // Output: 1
Symbol creates unique identifiers useful for object property keys to avoid name clashes.
const sym1 = Symbol('id');
const sym2 = Symbol('id');
console.log(sym1 === sym2); // Output: false
const obj = { [sym1]: 'value' };
console.log(obj[sym1]); // Output: value
Optional property access allows safely accessing a property on an object that might be null or undefined without throwing an error.
const person = { name: 'John', address: null }; console.log(person.address?.street); // Output: undefined console.log(person.name?.toUpperCase()); // Output: JOHN
Async/Await provides a way to write asynchronous code in a synchronous style, making it easier to read and maintain.
async function fetchData() { const response = await fetch('https://jsonplaceholder.typicode.com/todos/1'); const data = await response.json(); console.log(data); } fetchData();
Classes provide a blueprint for creating objects with properties and methods in a cleaner syntax than prototypes.
class Person { constructor(name, age) { this.name = name; this.age = age; } greet() { console.log(`Hello, my name is ${this.name}`); } } const john = new Person('John', 30); john.greet();
Map is a collection of keyed data items, just like an Object. But the keys can be of any type.
const map = new Map(); map.set('name', 'John'); map.set(1, 'one'); console.log(map.get('name')); console.log(map.get(1));
Set is a collection of values where each value must be unique.
const set = new Set(); set.add(1); set.add(2); set.add(1); // ignored console.log(set.size); console.log(set.has(2));
Symbol is a primitive data type that’s guaranteed to be unique. Often used to add hidden properties to objects.
const sym1 = Symbol('id'); const sym2 = Symbol('id'); console.log(sym1 === sym2);
Destructuring allows unpacking properties from objects into variables.
const user = { name: 'Alice', age: 25 }; const { name, age } = user; console.log(name); console.log(age);
Destructuring arrays allows extracting values into distinct variables.
const colors = ['red', 'green', 'blue']; const [first, second] = colors; console.log(first); console.log(second);
Default parameters allow named parameters to be initialized with default values if no value or undefined is passed.
function greet(name = 'Guest') { console.log(`Hello, ${name}`); } greet(); greet('Alice');
Rest parameters allow representing an indefinite number of arguments as an array.
function sum(...numbers) { return numbers.reduce((a, b) => a + b, 0); } console.log(sum(1, 2, 3)); console.log(sum(4, 5));
Spread syntax expands iterable elements like arrays into individual elements.
const nums = [1, 2, 3]; const newNums = [...nums, 4, 5]; console.log(newNums);