JavaScript is a high-level, interpreted programming language primarily used for creating interactive and dynamic content on web pages. It’s a core technology of the World Wide Web, alongside HTML and CSS.
Key features:
Example:
// A simple JavaScript function
function greet(name) {
console.log(`Hello, ${name}!`);
}
greet("World"); // Output: Hello, World!
JavaScript has several built-in data types:
Example:
let num = 42; // Number
let str = "Hello"; // String
let bool = true; // Boolean
let undef = undefined; // Undefined
let n = null; // Null
let sym = Symbol("unique"); // Symbol
let bigInt = 1234567890123456789012345678901234567890n; // BigInt
let obj = { // Object
name: "John",
age: 30
};
console.log(typeof num, typeof str, typeof bool, typeof undef, typeof n, typeof sym, typeof bigInt, typeof obj);
// Output: number string boolean undefined object symbol bigint object
null
and undefined
?While both null
and undefined
represent the absence of a value, they have distinct meanings:
Undefined:
Null:
Example:
let a;
console.log(a); // Output: undefined
let b = null;
console.log(b); // Output: null
console.log(typeof a); // Output: undefined
console.log(typeof b); // Output: object (this is a known quirk in JavaScript)
function greet(name) {
console.log(`Hello, ${name}!`);
}
greet(); // Output: Hello, undefined!
let obj = {
notHere: null
};
console.log(obj.notHere); // Output: null
console.log(obj.nonExistent); // Output: undefined
Hoisting is a behavior in JavaScript where variable and function declarations are moved to the top of their respective scopes during the compilation phase, before the code is executed.
Key points:
var
are hoisted and initialized with undefined
let
and const
are hoisted but not initialized (Temporal Dead Zone)Example:
console.log(x); // Output: undefined
var x = 5;
// The above is interpreted as:
var x;
console.log(x);
x = 5;
// Function hoisting
greet("World"); // Output: Hello, World!
function greet(name) {
console.log(`Hello, ${name}!`);
}
// let and const hoisting (Temporal Dead Zone)
console.log(y); // Throws ReferenceError
let y = 10;
Diagram: Hoisting Process
┌─────────────────────────────────┐
│ Memory allocation │
│ │
│ ┌───────────────────────────┐ │
│ │ Function declarations │ │
│ │ Variable declarations │ │
│ └───────────────────────────┘ │
│ ▼ │
│ ┌───────────────────────────┐ │
│ │ Code execution │ │
│ └───────────────────────────┘ │
└─────────────────────────────────┘
A closure is a function that has access to variables in its outer (enclosing) lexical scope, even after the outer function has returned. It’s a powerful feature that allows for data privacy and the creation of function factories.
Key characteristics:
Example:
function createCounter() {
let count = 0;
return function() {
count++;
console.log(count);
};
}
const counter = createCounter();
counter(); // Output: 1
counter(); // Output: 2
counter(); // Output: 3
Diagram: Closure Concept
┌───────────────────────────┐
│ createCounter │
│ ┌───────────────────────┐ │
│ │ count: 0 │ │
│ │ ┌───────────────────┐ │ │
│ │ │ returned function │ │ │
│ │ │ (closure) │ │ │
│ │ └───────────────────┘ │ │
│ └───────────────────────┘ │
└───────────────────────────┘
▼
┌───────────────────────────┐
│ counter │
│ (has access to count) │
└───────────────────────────┘
A callback function is a function passed as an argument to another function, which is then invoked inside the outer function to complete some kind of routine or action. Callbacks are fundamental to asynchronous programming in JavaScript.
Key points:
Example:
function fetchData(callback) {
setTimeout(() => {
const data = { id: 1, name: "John Doe" };
callback(data);
}, 1000);
}
function processData(data) {
console.log("Data processed:", data);
}
fetchData(processData);
// Output after 1 second: Data processed: { id: 1, name: "John Doe" }
Diagram: Callback Execution
┌────────────────┐ ┌────────────────┐
│ fetchData │ │ processData │
│ ┌──────────┐ │ │ │
│ │ setTimeout│ │ │ │
│ └──────────┘ │ │ │
│ │ │ │ │
│ ▼ │ │ │
│ ┌──────────┐ │ │ │
│ │ callback ├──┼───────┼───────────────▶│
│ └──────────┘ │ │ │
└────────────────┘ └────────────────┘
Promises are objects representing the eventual completion or failure of an asynchronous operation. They provide a cleaner alternative to callbacks for handling asynchronous code.
States of a Promise:
Key methods:
then()
: Handles the fulfillment of a promisecatch()
: Handles the rejection of a promisefinally()
: Executes regardless of the promise’s outcomeExample:
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const success = Math.random() > 0.5;
if (success) {
resolve({ id: 1, name: "John Doe" });
} else {
reject("Error fetching data");
}
}, 1000);
});
}
fetchData()
.then(data => console.log("Data received:", data))
.catch(error => console.error("Error:", error))
.finally(() => console.log("Operation completed"));
Diagram: Promise States
┌─────────────┐
│ Pending │
└─────┬───────┘
│
▼
┌─────────────┐ ┌─────────────┐
│ Fulfilled │ or │ Rejected │
└─────────────┘ └─────────────┘
setTimeout()
function?The setTimeout()
function is used to schedule the execution of a function after a specified delay in milliseconds. It’s part of the Web APIs in browsers and is commonly used for delaying operations or creating time-based animations.
Key points:
setTimeout()
is asynchronous and non-blockingclearTimeout()
Syntax:
setTimeout(function, delay, param1, param2, ...)
Example:
console.log("Start");
setTimeout(() => {
console.log("This message appears after 2 seconds");
}, 2000);
console.log("End");
// Output:
// Start
// End
// This message appears after 2 seconds (after 2 seconds)
Diagram: setTimeout Execution
┌─────────────────────────────────────────────────┐
│ Call Stack │
├─────────────────────────────────────────────────┤
│ 1. console.log("Start") │
│ 2. setTimeout(callback, 2000) │
│ 3. console.log("End") │
└─────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ Web API / Timer │
│ (waits for 2 seconds) │
└─────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ Callback Queue │
│ (callback function waiting to be executed) │
└─────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ Event Loop │
│ (moves callback to Call Stack when it's empty) │
└─────────────────────────────────────────────────┘
There are several ways to check if an array includes a certain value in JavaScript:
Using the includes()
method (ES6+):
This method returns true
if the array contains the specified element, and false
otherwise.
const fruits = ['apple', 'banana', 'orange'];
console.log(fruits.includes('banana')); // Output: true
console.log(fruits.includes('grape')); // Output: false
Using the indexOf()
method:
This method returns the index of the first occurrence of the specified element, or -1 if it’s not found.
const fruits = ['apple', 'banana', 'orange'];
console.log(fruits.indexOf('banana') !== -1); // Output: true
console.log(fruits.indexOf('grape') !== -1); // Output: false
Using the some()
method:
This method tests whether at least one element in the array passes the test implemented by the provided function.
const fruits = ['apple', 'banana', 'orange'];
console.log(fruits.some(fruit => fruit === 'banana')); // Output: true
console.log(fruits.some(fruit => fruit === 'grape')); // Output: false
Using a for loop (works for older browsers): This method manually iterates through the array to check for the value.
function includesValue(arr, value) {
for (let i = 0; i < arr.length; i++) {
if (arr[i] === value) {
return true;
}
}
return false;
}
const fruits = ['apple', 'banana', 'orange'];
console.log(includesValue(fruits, 'banana')); // Output: true
console.log(includesValue(fruits, 'grape')); // Output: false
The includes()
method is generally the most straightforward and readable option for modern JavaScript environments.
There are several ways to remove duplicates from an array in JavaScript:
Using Set (ES6+): This is the most concise method, leveraging the unique property of Set objects.
const numbers = [1, 2, 2, 3, 4, 4, 5];
const uniqueNumbers = [...new Set(numbers)];
console.log(uniqueNumbers); // Output: [1, 2, 3, 4, 5]
Using filter() method: This method creates a new array with unique elements by checking the index of each element.
const numbers = [1, 2, 2, 3, 4, 4, 5];
const uniqueNumbers = numbers.filter((value, index, self) =>
self.indexOf(value) === index
);
console.log(uniqueNumbers); // Output: [1, 2, 3, 4, 5]
Using reduce() method: This method builds a new array with unique elements by accumulating unique values.
const numbers = [1, 2, 2, 3, 4, 4, 5];
const uniqueNumbers = numbers.reduce((unique, item) =>
unique.includes(item) ? unique : [...unique, item], []
);
console.log(uniqueNumbers); // Output: [1, 2, 3, 4, 5]
Using forEach() with an object: This method uses an object to keep track of unique values.
const numbers = [1, 2, 2, 3, 4, 4, 5];
const uniqueNumbers = [];
const seen = {};
numbers.forEach(num => {
if (!seen[num]) {
seen[num] = true;
uniqueNumbers.push(num);
}
});
console.log(uniqueNumbers);