JavaScript All Important Concepts
Asynchronous Programming
Callbacks
Callbacks are functions passed as arguments to other functions to be executed later, often after a task completes. This approach enables asynchronous operations, ensuring that subsequent code does not wait for the completion of the initial task.
setTimeout
setTimeout schedules a function to be executed after a specified delay.
console.log('Start');
setTimeout(() => {
console.log('This message is delayed by 2 seconds');
}, 2000);
console.log('End');
Promises
Promises represent a value that may be available now, or in the future, or never. They enable more readable and manageable asynchronous code by providing .then() and .catch() methods for handling success and failure cases.
let promise = new Promise((resolve, reject) => {
let success = true; // Change to false to see the rejection
if(success) {
resolve('Promise resolved!');
} else {
reject('Promise rejected!');
}
});
promise.then((message) => {
console.log(message);
}).catch((error) => {
console.error(error);
});
Fetch
fetch is a modern, updated global function for making network requests. It returns a promise that is fulfilled once the response is available.
fetch('https://api.github.com')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
Async & Await
async functions always return a promise. await pauses the execution of the async function, waiting for the promise to resolve.
async function fetchData() {
try {
let response = await fetch('https://api.github.com');
let data = await response.json();
console.log(data);
} catch (error) {
console.error('Error:', error);
}
}
fetchData();
Callback Hell
Callback Hell occurs when multiple nested callbacks make the code hard to read and maintain.
// Callback Hell Example
doSomething(function(result) {
doSomethingElse(result, function(newResult) {
doThirdThing(newResult, function(finalResult) {
console.log('Got the final result: ' + finalResult);
}, failureCallback);
}, failureCallback);
}, failureCallback);
// Using Promises to Avoid Callback Hell
doSomething()
.then(result => doSomethingElse(result))
.then(newResult => doThirdThing(newResult))
.then(finalResult => console.log('Got the final result: ' + finalResult))
.catch(failureCallback);
// Using async/await to Avoid Callback Hell
async function asyncFunction() {
try {
let result = await doSomething();
let newResult = await doSomethingElse(result);
let finalResult = await doThirdThing(newResult);
console.log('Got the final result: ' + finalResult);
} catch (error) {
failureCallback(error);
}
}
asyncFunction();
JavaScript Closures and Scope
Scope
Scope determines the accessibility (visibility) of variables. JavaScript has two types of scope:
- Global Scope: A variable declared outside a function becomes a global variable and is accessible from any part of the code.
- Local Scope: A variable declared inside a function is local to that function and cannot be accessed from outside the function.
Closures
A closure is a function having access to the parent scope, even after the parent function has closed. Closures are created every time a function is created.
function outerFunction() {
let outerVariable = 'I am outside!';
function innerFunction() {
console.log(outerVariable);
}
return innerFunction;
}
const inner = outerFunction();
inner(); // Outputs: I am outside!
Understanding the DOM
Nodes and Elements
The DOM tree consists of different types of nodes:
- Element Nodes: Represent HTML tags (e.g.,
<div>,<p>,<a>). - Attribute Nodes: Represent attributes of HTML tags (e.g., class, id).
- Text Nodes: Represent the text inside HTML elements.
Accessing DOM Elements
You can access DOM elements using various methods:
document.getElementById('id'): Selects an element by its ID.document.getElementsByClassName('class'): Selects elements by their class name.document.getElementsByTagName('tag'): Selects elements by their tag name.document.querySelector('selector'): Selects the first element that matches a CSS selector.document.querySelectorAll('selector'): Selects all elements that match a CSS selector.
Manipulating DOM Elements
You can modify DOM elements using JavaScript:
- Creating Elements:
document.createElement('tag') - Appending Elements:
parent.appendChild(child) - Removing Elements:
parent.removeChild(child) - Setting Attributes:
element.setAttribute('attribute', 'value') - Modifying Inner HTML:
element.innerHTML = 'new content' - Modifying Text Content:
element.textContent = 'new text'
ES6+ Syntax and Features
Let and Const
In ES6, both let and const are used to declare variables, but they have key differences.
- let: Block-scoped variable, unlike
var, which is function-scoped.
let x = 10;
if (true) {
let x = 20; // Different variable than the outer x
}
console.log(x); // 10
- const: Block-scoped constant, which cannot be reassigned.
const y = 5;
y = 10; // Error: Assignment to constant variable.
Arrow Functions
Arrow functions provide a shorter syntax and lexically bind this.
// Traditional Function
function add(a, b) {
return a + b;
}
// Arrow Function
const add = (a, b) => a + b;
Template Literals
Template literals provide an easier way to create strings and include expressions.
let name = 'John';
let greeting = `Hello, ${name}!`;
console.log(greeting); // Outputs: Hello, John!
Destructuring
Destructuring allows unpacking values from arrays or properties from objects into distinct variables.
// Array Destructuring
let [a, b] = [1, 2];
console.log(a); // 1
console.log(b); // 2
// Object Destructuring
let {name, age} = {name: 'John', age: 30};
console.log(name); // John
console.log(age); // 30
Rest and Spread Operators
The rest operator ... collects all remaining elements into an array, while the spread operator ... expands an array into individual elements.
// Rest Operator
function sum(...numbers) {
return numbers.reduce((total, num) => total + num);
}
console.log(sum(1, 2, 3)); // 6
// Spread Operator
let arr = [1, 2, 3];
let newArr = [...arr, 4, 5];
console.log(newArr); // [1, 2, 3, 4, 5]