JavaScript has 8 data types: 7 primitive types and 1 non-primitive type.
// Examples
let num = 42; // Number
let str = "Hello"; // String
let bool = true; // Boolean
let undef; // Undefined
let empty = null; // Null
let sym = Symbol('id'); // Symbol
let big = 123456789012345678901234567890n; // BigInt
let obj = { name: "John" }; // Object
function greet(name) {
return `Hello, ${name}!`;
}
const greet = function(name) {
return `Hello, ${name}!`;
};
const greet = (name) => `Hello, ${name}!`;
(function() {
console.log("This runs immediately!");
})();
Hoisting is JavaScript's behavior of moving variable and function declarations to the top of their scope during compilation.
console.log(x); // undefined (not error)
var x = 5;
// This is how JavaScript interprets it:
var x;
console.log(x); // undefined
x = 5;
sayHello(); // "Hello!" - works fine
function sayHello() {
console.log("Hello!");
}
console.log(y); // ReferenceError
let y = 10;
console.log(z); // ReferenceError
const z = 20;
Key Point: let and const are hoisted but in a "temporal dead zone" until declaration.
A closure is a function that has access to variables in its outer (enclosing) scope even after the outer function returns.
function outer(x) {
// Outer function's variable
function inner(y) {
// Inner function has access to 'x'
return x + y;
}
return inner;
}
const add5 = outer(5);
console.log(add5(3)); // 8
function createCounter() {
let count = 0;
return {
increment: () => ++count,
decrement: () => --count,
getCount: () => count
};
}
const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.getCount()); // 1
The value of this depends on how a function is called.
console.log(this); // Window object (browser) or global (Node.js)
const obj = {
name: "John",
greet() {
console.log(this.name); // "John"
}
};
obj.greet();
const obj = {
name: "John",
greet: () => {
console.log(this.name); // undefined (inherits from parent scope)
}
};
function greet() {
console.log(`Hello, ${this.name}`);
}
const person = { name: "Alice" };
greet.call(person); // "Hello, Alice"
greet.apply(person); // "Hello, Alice"
const boundGreet = greet.bind(person);
boundGreet(); // "Hello, Alice"
// Object literal
const person = {
name: "John",
age: 30
};
// Constructor function
function Person(name, age) {
this.name = name;
this.age = age;
}
const john = new Person("John", 30);
// Object.create()
const personProto = {
greet() { console.log(`Hi, I'm ${this.name}`); }
};
const alice = Object.create(personProto);
alice.name = "Alice";
Object.keys() - Returns array of property namesObject.values() - Returns array of property valuesObject.entries() - Returns array of [key, value] pairsObject.assign() - Copies properties from source to targetObject.freeze() - Makes object immutableEvery JavaScript object has a prototype. Objects inherit properties and methods from their prototype.
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
console.log(`${this.name} makes a sound`);
};
function Dog(name, breed) {
Animal.call(this, name);
this.breed = breed;
}
// Set up inheritance
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() {
console.log(`${this.name} barks`);
};
const dog = new Dog("Buddy", "Golden Retriever");
dog.speak(); // "Buddy makes a sound"
dog.bark(); // "Buddy barks"
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a sound`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name);
this.breed = breed;
}
bark() {
console.log(`${this.name} barks`);
}
}
JavaScript is single-threaded but uses an event loop to handle asynchronous operations.
console.log("1");
setTimeout(() => {
console.log("2");
}, 0);
console.log("3");
// Output: 1, 3, 2
A Promise is an object representing the eventual completion or failure of an asynchronous operation.
const myPromise = new Promise((resolve, reject) => {
const success = true;
setTimeout(() => {
if (success) {
resolve("Operation successful!");
} else {
reject("Operation failed!");
}
}, 1000);
});
// Using the promise
myPromise
.then(result => console.log(result))
.catch(error => console.error(error))
.finally(() => console.log("Cleanup"));
Promise.all() - Waits for all promises to resolvePromise.race() - Resolves with first settled promisePromise.allSettled() - Waits for all promises to settlePromise.resolve() - Returns resolved promisePromise.reject() - Returns rejected promiseAsync/await is syntactic sugar over Promises, making asynchronous code look more like synchronous code.
async function fetchData() {
try {
const response = await fetch('/api/data');
const data = await response.json();
return data;
} catch (error) {
console.error('Error:', error);
throw error;
}
}
// Usage
fetchData()
.then(data => console.log(data))
.catch(error => console.error(error));
async function fetchMultiple() {
// Sequential (slower)
const data1 = await fetch('/api/data1');
const data2 = await fetch('/api/data2');
// Parallel (faster)
const [response1, response2] = await Promise.all([
fetch('/api/data1'),
fetch('/api/data2')
]);
}
async function handleErrors() {
try {
const result = await fetch('/api/data');
if (!result.ok) {
throw new Error(`HTTP error! status: ${result.status}`);
}
return await result.json();
} catch (error) {
console.error('Fetch failed:', error);
// Handle different error types
if (error.name === 'TypeError') {
// Network error
console.log('Network error occurred');
}
throw error;
}
}
Delays execution until after a specified time has passed since the last invocation.
function debounce(func, delay) {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
func.apply(this, args);
}, delay);
};
}
// Usage
const searchInput = document.getElementById('search');
const debouncedSearch = debounce((value) => {
console.log('Searching for:', value);
}, 300);
searchInput.addEventListener('input', (e) => {
debouncedSearch(e.target.value);
});
Limits execution to at most once per specified time interval.
function throttle(func, limit) {
let inThrottle;
return function(...args) {
if (!inThrottle) {
func.apply(this, args);
inThrottle = true;
setTimeout(() => {
inThrottle = false;
}, limit);
}
};
}
// Usage
const throttledScroll = throttle(() => {
console.log('Scroll event handled');
}, 100);
window.addEventListener('scroll', throttledScroll);
// By ID
const element = document.getElementById('myId');
// By Class
const elements = document.getElementsByClassName('myClass');
const element = document.querySelector('.myClass');
const allElements = document.querySelectorAll('.myClass');
// By Tag
const paragraphs = document.getElementsByTagName('p');
// Create element
const div = document.createElement('div');
div.textContent = 'Hello World';
div.className = 'my-class';
div.setAttribute('data-id', '123');
// Append to DOM
document.body.appendChild(div);
// Modify existing element
const existing = document.querySelector('#existing');
existing.innerHTML = 'Updated content';
existing.style.backgroundColor = 'blue';
// Add event listener
button.addEventListener('click', function(event) {
event.preventDefault();
console.log('Button clicked!');
});
// Remove event listener
button.removeEventListener('click', handler);
// Event delegation
document.addEventListener('click', function(event) {
if (event.target.classList.contains('button')) {
console.log('Delegated click');
}
});
try {
// Code that might throw an error
const result = JSON.parse(invalidJSON);
} catch (error) {
// Handle the error
console.error('Parsing failed:', error.message);
} finally {
// Always executed
console.log('Cleanup completed');
}
class ValidationError extends Error {
constructor(message, field) {
super(message);
this.name = 'ValidationError';
this.field = field;
}
}
function validateEmail(email) {
if (!email.includes('@')) {
throw new ValidationError('Invalid email format', 'email');
}
}
try {
validateEmail('invalid-email');
} catch (error) {
if (error instanceof ValidationError) {
console.log(`Validation failed for ${error.field}: ${error.message}`);
}
}
// Handle uncaught errors
window.addEventListener('error', function(event) {
console.error('Global error:', event.error);
});
// Handle unhandled promise rejections
window.addEventListener('unhandledrejection', function(event) {
console.error('Unhandled promise rejection:', event.reason);
event.preventDefault(); // Prevent default browser behavior
});
// Traditional function
function add(a, b) {
return a + b;
}
// Arrow function
const add = (a, b) => a + b;
// With single parameter (parentheses optional)
const square = x => x * x;
// With block body
const processData = (data) => {
const processed = data.map(item => item * 2);
return processed.filter(item => item > 10);
};
// Array destructuring
const [first, second, ...rest] = [1, 2, 3, 4, 5];
// Object destructuring
const { name, age, city = 'Unknown' } = person;
// Function parameter destructuring
function greet({ name, age }) {
console.log(`Hello ${name}, you are ${age} years old`);
}
const name = 'John';
const age = 30;
// Multi-line strings
const message = `Hello ${name},
You are ${age} years old.
Welcome to JavaScript!`;
// Tagged templates
function highlight(strings, ...values) {
return strings.reduce((result, string, i) => {
const value = values[i] ? `${values[i]}` : '';
return result + string + value;
}, '');
}
// Spread operator
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 }; // { a: 1, b: 2, c: 3 }
// Rest parameters
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
'use strict';vargetUserData() instead of getData()clearTimeout(), clearInterval()