Complete JavaScript Notes 1. Introduction to JavaScript JavaScript is a versatile and powerful programming language primarily known for its role in web development. It enables interactive and dynamic content on websites, making them more engaging and user-friendly. Beyond web browsers, JavaScript has expanded its reach to various other domains, including server-side development with Node.js, mobile app development with frameworks like React Native, and even desktop applications. What is JavaScript? JavaScript is a high-level, interpreted programming language that conforms to the ECMAScript specification. It is a multi-paradigm language, supporting event-driven, functional, and imperative programming styles. Unlike compiled languages, JavaScript code is executed directly by an interpreter, typically within a web browser's JavaScript engine or a Node.js runtime environment. History and Evolution JavaScript was created in 1995 by Brendan Eich while he was working at Netscape Communications. Initially named LiveScript, it was quickly renamed JavaScript to capitalize on the popularity of Java at the time, despite having little to no direct relation to the Java programming language. The language was standardized under ECMAScript in 1997, and subsequent versions have introduced significant enhancements and new features, such as ES6 (ECMAScript 2015), which brought major improvements like arrow functions, classes, and modules. Where is JavaScript used? JavaScript's primary domain remains web development, where it powers the client- side interactivity of millions of websites. However, its applications have diversified considerably:
Front-end Web Development: Used with HTML and CSS to create dynamic and interactive user interfaces. Frameworks and libraries like React, Angular, and Vue.js are built on JavaScript. Back-end Web Development: With Node.js, JavaScript can be used to build scalable and high-performance server-side applications, APIs, and microservices. Mobile App Development: Frameworks such as React Native and NativeScript allow developers to build cross-platform mobile applications using JavaScript. Desktop App Development: Electron and NW.js enable the creation of desktop applications using web technologies (HTML, CSS, JavaScript). Game Development: JavaScript can be used to develop browser-based games and even more complex games with libraries like Phaser. IoT (Internet of Things): JavaScript can be used to program various IoT devices. Setting up your development environment To start writing and running JavaScript code, you primarily need a text editor and a web browser. For more advanced development, a dedicated Integrated Development Environment (IDE) and Node.js are recommended. 1. Text Editor/IDE: Popular choices include Visual Studio Code, Sublime Text, Atom, or WebStorm. These provide features like syntax highlighting, autocompletion, and debugging tools. 2. Web Browser: Modern web browsers (Chrome, Firefox, Edge, Safari) come with built-in JavaScript engines and developer tools (console, debugger) that are essential for testing and debugging client-side JavaScript. 3. Node.js: For server-side JavaScript development and to use JavaScript outside the browser, install Node.js. It includes the npm (Node Package Manager) which is crucial for managing project dependencies and running development tools. 2. JavaScript Basics JavaScript's fundamental building blocks include variables, data types, operators, and control flow statements. Understanding these concepts is crucial for writing any JavaScript program.
Variables (var, let, const) Variables are containers for storing data values. JavaScript provides three keywords to declare variables: var : Historically used for variable declaration. var declarations are function- scoped and are hoisted to the top of their function or global scope. This can lead to unexpected behavior, especially in loops or conditional blocks. javascript var x = 10; if (true) { var x = 20; // Same variable x console.log(x); // 20 } console.log(x); // 20 let : Introduced in ES6 (ECMAScript 2015), let declarations are block-scoped. This means the variable is only accessible within the block (e.g., if statement, for loop) where it is defined. javascript let y = 10; if (true) { let y = 20; // Different variable y console.log(y); // 20 } console.log(y); // 10 const : Also introduced in ES6, const is used to declare constants. Like let , const declarations are block-scoped. Once a const variable is assigned a value, it cannot be reassigned. However, for objects and arrays declared with const , their properties or elements can still be modified. ```javascript const PI = 3.14; // PI = 3.14159; // This would cause an error const person = { name: "Alice" }; person.name = "Bob"; // This is allowed console.log(person.name); // Bob ``` Data Types (Primitive and Non-Primitive) JavaScript has several built-in data types. They are broadly categorized into primitive and non-primitive (or reference) types. Primitive Data Types: String : Represents textual data. Enclosed in single quotes ( '...' ), double quotes (` "..." ), or backticks ( `...` for template literals). javascript let name = "John Doe"; * Number : Represents both integer and floating-point numbers. javascript
let age = 30; let price = 99.99; * Boolean : Represents a logical entity and can have two values: true or false . javascript let isActive = true; * Undefined : Represents a variable that has been declared but has not yet been assigned a value. javascript let city; // city is undefined * Null : Represents the intentional absence of any object value. It is a primitive value. javascript let car = null; * Symbol : (ES6) Represents a unique identifier. Used to create unique property keys that won't clash with other property keys. javascript const id = Symbol('id'); * BigInt : (ES2020) Represents whole numbers larger than 2^53 - 1, which is the largest number JavaScript can reliably represent with the Number primitive. javascript const bigNumber = 1234567890123456789012345678901234567890n; Non-Primitive (Reference) Data Types: Object : A collection of key-value pairs. Objects are the most fundamental non- primitive data type. javascript let person = { firstName: "John", lastName: "Doe" }; Array : A special type of object used to store ordered collections of data. javascript let colors = ["red", "green", "blue"]; Function : A block of code designed to perform a particular task. Functions are also objects in JavaScript. javascript function greet(name) { return "Hello, " + name; } Operators (Arithmetic, Assignment, Comparison, Logical, etc.) Operators are symbols that perform operations on operands (values and variables). Arithmetic Operators: Perform mathematical calculations.
Operator Description Example + Addition x + y - Subtraction x - y * Multiplication x * y / Division x / y % Modulus x % y ** Exponentiation x ** y ++ Increment x++ or ++x -- Decrement x-- or --x Assignment Operators: Assign values to variables. Operator Example Same As = x = y x = y += x += y x = x + y -= x -= y x = x - y *= x *= y x = x * y /= x /= y x = x / y %= x %= y x = x % y **= x **= y x = x ** y Comparison Operators: Compare two values and return a boolean result.
Operator Description Example == Equal to (loose equality) x == y === Equal value and type (strict equality) x === y != Not equal (loose inequality) x != y !== Not equal value or type (strict inequality) x !== y > Greater than x > y < Less than x < y >= Greater than or equal to x >= y <= Less than or equal to x <= y Logical Operators: Combine conditional statements. Operator Description Example && Logical AND x < 10 && x > 5 || Logical OR x < 5 || x > 10 ! Logical NOT !(x === 5) Type Conversion (Implicit and Explicit) JavaScript is a loosely typed language, meaning variables do not have a fixed type. Values can be converted from one type to another, either implicitly (coercion) or explicitly. Implicit Type Conversion (Coercion): JavaScript automatically converts data types when an operation involves different types. javascript console.log("5" + 5); // "55" (Number 5 is converted to String "5") console.log("5" - 5); // 0 (String "5" is converted to Number 5) console.log(true + 1); // 2 (Boolean true is converted to Number 1)
Explicit Type Conversion: Developers explicitly convert data types using built-in functions or methods. javascript console.log(Number("10")); // 10 console.log(String(100)); // "100" console.log(Boolean(0)); // false Conditional Statements (if, else if, else, switch) Conditional statements execute different actions based on different conditions. if , else if , else : javascript let hour = 14; if (hour < 12) { console.log("Good morning!"); } else if (hour < 18) { console.log("Good afternoon!"); } else { console.log("Good evening!"); } switch : Used to perform different actions based on different conditions. javascript let day = "Monday"; switch (day) { case "Monday": console.log("It's Monday."); break; case "Friday": console.log("It's Friday!"); break; default: console.log("It's another day."); } Loops (for, while, do-while, for...in, for...of) Loops are used to execute a block of code repeatedly. for loop: Iterates a block of code a number of times. javascript for (let i = 0; i < 5; i++) { console.log(i); } while loop: Executes a block of code as long as a specified condition is true. javascript let i = 0; while (i < 5) { console.log(i); i++; } do...while loop: Similar to while , but the block of code is executed at least once before the condition is tested. javascript let i = 0; do { console.log(i); i++; } while (i < 5); for...in loop: Iterates over the enumerable properties of an object.
javascript const person = { fname: "John", lname: "Doe", age: 25 }; for (let x in person) { console.log(x + ": " + person[x]); } for...of loop: (ES6) Iterates over iterable objects (like Arrays, Strings, Maps, Sets, etc.). javascript const colors = ["red", "green", "blue"]; for (let color of colors) { console.log(color); } 3. Functions Functions are fundamental building blocks in JavaScript. They are reusable blocks of code that perform a specific task. Functions allow you to organize your code, make it more modular, and avoid repetition (DRY - Don't Repeat Yourself principle). Function Declaration and Expression There are two primary ways to define functions in JavaScript: Function Declaration (or Function Statement): This is the most common way to define a function. Function declarations are hoisted, meaning they can be called before they are defined in the code. ```javascript // Function Declaration function greet(name) { return "Hello, " + name + "!"; } console.log(greet("Alice")); // Output: Hello, Alice! ``` Function Expression: A function expression defines a function as part of an expression, typically assigned to a variable. Function expressions are not hoisted, so they cannot be called before they are defined. ```javascript // Function Expression const sayHello = function(name) { return "Hello, " + name + "!"; }; console.log(sayHello("Bob")); // Output: Hello, Bob! // console.log(anotherGreet("Charlie")); // This would cause an error if called before definition ```
Arrow Functions Arrow functions (introduced in ES6) provide a more concise syntax for writing function expressions. They also behave differently regarding the this keyword (which will be discussed in a later section). Basic Syntax: javascript const add = (a, b) => a + b; console.log(add(5, 3)); // Output: 8 Single Parameter: Parentheses are optional for a single parameter. javascript const square = num => num * num; console.log(square(4)); // Output: 16 No Parameters: Empty parentheses are required. javascript const sayHi = () => "Hi there!"; console.log(sayHi()); // Output: Hi there! Block Body: For multiple statements, use curly braces and a return statement. javascript const calculateArea = (length, width) => { const area = length * width; return `The area is ${area} square units.`; }; console.log(calculateArea(10, 5)); // Output: The area is 50 square units. Parameters and Arguments Parameters: Named variables listed in the function definition. They act as placeholders for the values that will be passed into the function. Arguments: The actual values passed to the function when it is called. ```javascript function multiply(a, b) { // a and b are parameters return a * b; } console.log(multiply(7, 2)); // 7 and 2 are arguments ```
Return Values Functions can return a value using the return statement. If no return statement is specified, or if return; is used without a value, the function implicitly returns undefined . function getMax(x, y) { if (x > y) { return x; } else { return y; } } let result = getMax(15, 8); console.log(result); // Output: 15 function doNothing() { // No return statement } console.log(doNothing()); // Output: undefined Scope (Global, Local, Block) Scope determines the accessibility of variables, objects, and functions in different parts of your code. Global Scope: Variables declared outside any function or block have global scope. They can be accessed from anywhere in the code. ```javascript let globalVar = "I am global"; function accessGlobal() { console.log(globalVar); } accessGlobal(); // Output: I am global ``` Function (Local) Scope: Variables declared inside a function (using var , let , or const ) are function-scoped. They are only accessible within that function. javascript function localScopeExample() { var localVar = "I am local (var)"; let anotherLocalVar = "I am local (let)"; const PI = 3.14; // Also local console.log(localVar); console.log(anotherLocalVar); } localScopeExample(); // console.log(localVar); // Error: localVar is not defined
Block Scope: Variables declared with let and const inside a block (e.g., if statement, for loop, or any {} block) are block-scoped. They are only accessible within that block. javascript if (true) { let blockVar = "I am block-scoped"; console.log(blockVar); // Output: I am block-scoped } // console.log(blockVar); // Error: blockVar is not defined Closures A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In simpler terms, a closure gives you access to an outer function's scope from an inner function, even after the outer function has finished executing. function outerFunction(outerVariable) { return function innerFunction(innerVariable) { console.log("Outer Variable: " + outerVariable); console.log("Inner Variable: " + innerVariable); }; } const newFunction = outerFunction("Hello"); newFunction("World"); // Output: // Outer Variable: Hello // Inner Variable: World // Even after outerFunction has returned, innerFunction still has access to outerVariable Closures are powerful for creating private variables and functions, and for implementing patterns like currying and memoization. Immediately Invoked Function Expressions (IIFE) An IIFE is a JavaScript function that runs as soon as it is defined. It's a design pattern that creates a private scope for variables, preventing them from polluting the global namespace.
(function() { var privateVar = "I am private"; console.log(privateVar); })(); // The function is immediately invoked // console.log(privateVar); // Error: privateVar is not defined // IIFE with parameters (function(message) { console.log(message); })("This is an IIFE with a parameter."); IIFEs are commonly used in older JavaScript codebases to encapsulate modules and prevent variable collisions. 4. Objects and Arrays Objects and Arrays are fundamental data structures in JavaScript, used for storing collections of data. They are both types of objects, but serve different purposes and have distinct characteristics. Objects (Creation, Properties, Methods) An object in JavaScript is a standalone entity, with properties and type. Objects are collections of key-value pairs. The keys (or property names) are strings (or Symbols), and the values can be any data type, including other objects, functions, or primitive values. Creation of Objects: 1. Object Literal (Recommended for simple objects): The simplest way to create an object. javascript const person = { firstName: "John", lastName: "Doe", age: 30, isStudent: false, // A method (function as a property) greet: function() { return `Hello, my name is $`{this.firstName} `${this.lastName}.`; } }; 2. new Object() (Less common): javascript const car = new Object(); car.make = "Toyota"; car.model = "Camry";
3. Constructor Function: Used to create multiple objects of the same type. ``javascript function Book(title, author, year) { this.title = title; this.author = author; this.year = year; this.getSummary = function() { return $ {this.title} by ${this.author}, published in ${this.year}.`; }; } const book1 = new Book("The Hobbit", "J.R.R. Tolkien", 1937); console.log(book1.getSummary()); ``` 4. class Keyword (ES6): Syntactic sugar over constructor functions and prototypes. ```javascript class Animal { constructor(name, species) { this.name = name; this.species = species; } makeSound() { console.log("Generic animal sound"); } } const dog = new Animal("Buddy", "Dog"); dog.makeSound(); ``` Accessing Properties: Dot Notation (Recommended): javascript console.log(person.firstName); // "John" Bracket Notation (Useful for dynamic property names or properties with special characters): javascript console.log(person["lastName"]); // "Doe" let prop = "age"; console.log(person[prop]); // 30 Modifying Properties: person.age = 31; person["isStudent"] = true; console.log(person.age); // 31 console.log(person.isStudent); // true Adding New Properties:
person.nationality = "American"; console.log(person.nationality); // "American" Deleting Properties: delete person.isStudent; console.log(person.isStudent); // undefined Methods: Functions stored as object properties. console.log(person.greet()); // "Hello, my name is John Doe." Arrays (Creation, Methods, Iteration) Arrays are ordered collections of values. Each value is called an element, and each element has a numeric position called an index (starting from 0). Creation of Arrays: 1. Array Literal (Recommended): javascript const fruits = ["apple", "banana", "cherry"]; const numbers = [1, 2, 3, 4, 5]; const mixed = ["text", 123, true, { key: "value" }]; 2. new Array() (Less common): javascript const emptyArray = new Array(); const fiveElements = new Array(5); // Creates an array with 5 empty slots const colors = new Array("red", "green", "blue"); Accessing Elements: Elements are accessed using their index in bracket notation. console.log(fruits[0]); // "apple" console.log(fruits[2]); // "cherry" console.log(fruits.length); // 3 Modifying Elements:
fruits[1] = "grape"; console.log(fruits); // ["apple", "grape", "cherry"] Common Array Methods: JavaScript provides a rich set of built-in methods for manipulating arrays.
Method Description Example push() Adds one or more elements to the end of an array and returns the new length. arr.push("new") pop() Removes the last element from an array and returns that element. arr.pop() shift() Removes the first element from an array and returns that element. arr.shift() unshift() Adds one or more elements to the beginning of an array and returns the new length. arr.unshift("first") splice() Changes the contents of an array by removing or replacing existing elements and/or adding new elements in place. arr.splice(index, deleteCount, item1, ...) slice() Returns a shallow copy of a portion of an array into a new array object. arr.slice(startIndex, endIndex) concat() Used to merge two or more arrays. arr1.concat(arr2) indexOf() Returns the first index at which a given element can be found in the array, or -1 if it is not present. arr.indexOf("item") includes() Determines whether an array includes a certain value among its entries, returning true or false as appropriate. arr.includes("item") forEach() Executes a provided function once for each array element. arr.forEach(callback) map() Creates a new array populated with the results of calling a provided function on every element in the calling array. arr.map(callback) filter() Creates a new array with all elements that pass the test implemented by the provided function. arr.filter(callback)
Method Description Example reduce() Executes a reducer function (that you provide) on each element of the array, resulting in single output value. arr.reduce(callback, initialValue) find() Returns the value of the first element in the provided array that satisfies the provided testing function. arr.find(callback) sort() Sorts the elements of an array in place and returns the sorted array. arr.sort() reverse() Reverses an array in place. arr.reverse() Iteration over Arrays: for loop: javascript for (let i = 0; i < fruits.length; i++) { console.log(fruits[i]); } forEach() method: javascript fruits.forEach(function(fruit, index) { console.log(`$`{index}: `${fruit}`); }); for...of loop (ES6): javascript for (const fruit of fruits) { console.log(fruit); } Destructuring (Object and Array) Destructuring assignment is a special syntax that allows you to unpack values from arrays, or properties from objects, into distinct variables. Object Destructuring: ```javascript const person = { name: "Alice", age: 25, city: "New York" }; const { name, age } = person; console.log(name); // "Alice" console.log(age); // 25
// Renaming variables const { name: personName, city: personCity } = person; console.log(personName); // "Alice" console.log(personCity); // "New York" ``` Array Destructuring: ```javascript const colors = ["red", "green", "blue"]; const [firstColor, secondColor] = colors; console.log(firstColor); // "red" console.log(secondColor); // "green" // Skipping elements const [,, thirdColor] = colors; console.log(thirdColor); // "blue" // With rest operator const [primary, ...restColors] = colors; console.log(primary); // "red" console.log(restColors); // ["green", "blue"] ``` Spread and Rest Operators Both the spread ( ... ) and rest ( ... ) operators use the same syntax but serve different purposes based on where they are used. Spread Operator ( ... ): Expands an iterable (like an array or string) into individual elements. Useful for copying arrays, merging arrays, or passing multiple arguments to a function. ```javascript // Copying an array const originalArray = [1, 2, 3]; const copiedArray = [...originalArray]; // [1, 2, 3] // Merging arrays const arr1 = [1, 2]; const arr2 = [3, 4]; const mergedArray = [...arr1, ...arr2]; // [1, 2, 3, 4] // Spreading properties in objects (ES2018) const obj1 = { a: 1, b: 2 }; const obj2 = { c: 3, d: 4 }; const mergedObject = { ...obj1, ...obj2 }; // { a: 1, b: 2, c: 3, d: 4 } // Passing arguments to a function function sum(a, b, c) { return a + b + c; } const nums = [1, 2, 3]; console.log(sum(...nums)); // 6 ``` Rest Operator ( ... ): Collects multiple elements into an array. Used in function parameters to handle an indefinite number of arguments, or in destructuring assignments. ```javascript // In function parameters function collectArgs(firstArg, ...restArgs) { console.log(firstArg); // "A" console.log(restArgs); // ["B", "C", "D"] }
collectArgs("A", "B", "C", "D"); // In array destructuring (as shown above) const [head, ...tail] = [1, 2, 3, 4]; console.log(head); // 1 console.log(tail); // [2, 3, 4] ``` 5. Asynchronous JavaScript JavaScript is a single-threaded language, meaning it can only execute one task at a time. However, many operations, such as fetching data from a server, reading a file, or waiting for a user action, can take time. If these operations were synchronous (blocking), the entire application would freeze until they completed. Asynchronous programming allows JavaScript to handle these long-running tasks without blocking the main thread, ensuring a smooth and responsive user experience. Callbacks A callback 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. This is the traditional way of handling asynchronous operations in JavaScript. function fetchData(callback) { // Simulate a network request setTimeout(() => { const data = { message: "Data fetched successfully!" }; callback(null, data); // Pass null for error, and data on success }, 2000); } console.log("Fetching data..."); fetchData((error, data) => { if (error) { console.error("Error:", error); } else { console.log(data.message); } }); console.log("This will be logged before the data is fetched."); Callback Hell (Pyramid of Doom): When multiple asynchronous operations depend on each other, you can end up with nested callbacks, which makes the code hard to read and maintain. This is known as "callback hell."
Promises (States, Chaining, Error Handling) Promises, introduced in ES6, provide a cleaner and more robust way to handle asynchronous operations. A Promise is an object representing the eventual completion (or failure) of an asynchronous operation and its resulting value. Promise States: pending : Initial state, neither fulfilled nor rejected. fulfilled : The operation completed successfully. rejected : The operation failed. Creating a Promise: const myPromise = new Promise((resolve, reject) => { // Asynchronous operation setTimeout(() => { const success = true; if (success) { resolve("Promise resolved!"); } else { reject("Promise rejected!"); } }, 2000); }); Consuming a Promise: myPromise .then(result => { console.log(result); // "Promise resolved!" }) .catch(error => { console.error(error); // "Promise rejected!" }) .finally(() => { console.log("Promise finished."); }); Promise Chaining: Promises can be chained together to handle a sequence of asynchronous operations.
fetch('https://api.example.com/data') .then(response => response.json()) // .json() also returns a promise .then(data => { console.log(data); }) .catch(error => { console.error('Error fetching data:', error); }); Async/Await async/await , introduced in ES2017, is syntactic sugar built on top of Promises. It allows you to write asynchronous code that looks and behaves more like synchronous code, making it easier to read and reason about. async function: A function declared with the async keyword automatically returns a Promise . await operator: The await operator is used to wait for a Promise to resolve. It can only be used inside an async function. async function fetchDataAsync() { try { console.log("Fetching data..."); const response = await fetch('https://api.example.com/data'); const data = await response.json(); console.log(data); } catch (error) { console.error('Error:', error); } } fetchDataAsync(); Event Loop The Event Loop is the mechanism that allows JavaScript to perform non-blocking asynchronous operations, despite being single-threaded. It continuously checks the message queue for new messages (tasks) and executes them. 1. Call Stack: Where function calls are pushed and popped. 2. Web APIs (Browser) / C++ APIs (Node.js): Handle asynchronous operations (e.g., setTimeout , fetch ).
3. Message Queue (or Task Queue): Where callback functions are placed after the asynchronous operation is complete. 4. Event Loop: When the Call Stack is empty, the Event Loop takes the first message from the Message Queue and pushes it onto the Call Stack for execution. This model ensures that the main thread is not blocked by long-running operations, allowing the user interface to remain responsive. 6. DOM Manipulation The Document Object Model (DOM) is a programming interface for web documents. It represents the page structure as a tree of objects, where each object corresponds to a part of the document, such as an element, attribute, or text. JavaScript can interact with this DOM tree to dynamically change the content, structure, and style of a web page. What is the DOM? When a web page is loaded, the browser creates a DOM of the page. The DOM is a platform- and language-neutral interface that allows programs and scripts to dynamically access and update the content, structure, and style of documents. It represents the document as nodes and objects. For example, consider this simple HTML: <!DOCTYPE html> <html> <head> <title>My Page</title> </head> <body> <h1 id="main-title">Hello, DOM!</h1> <p class="intro">This is a paragraph.</p> <button>Click Me</button> </body> </html> The DOM represents this as a tree structure, where document is the root, html is its child, and so on.
Selecting Elements To manipulate elements, you first need to select them. JavaScript provides several methods for this: document.getElementById() : Selects a single element by its id attribute. Returns null if the element is not found. javascript const titleElement = document.getElementById("main- title"); console.log(titleElement.textContent); // "Hello, DOM!" document.getElementsByClassName() : Selects all elements with a specific class name. Returns an HTMLCollection (live collection). javascript const introParagraphs = document.getElementsByClassName("intro"); console.log(introParagraphs[0].textContent); // "This is a paragraph." document.getElementsByTagName() : Selects all elements with a specific tag name. Returns an HTMLCollection. javascript const allParagraphs = document.getElementsByTagName("p"); console.log(allParagraphs.length); // 1 document.querySelector() : Selects the first element that matches a specified CSS selector. This is a very versatile method. javascript const firstParagraph = document.querySelector("p.intro"); console.log(firstParagraph.textContent); // "This is a paragraph." const button = document.querySelector("button"); document.querySelectorAll() : Selects all elements that match a specified CSS selector. Returns a NodeList (static collection). javascript const allElements = document.querySelectorAll("h1, p"); allElements.forEach(el => console.log(el.tagName)); // H1, P
Modifying HTML Content and Attributes Once you have selected an element, you can modify its content and attributes. textContent : Gets or sets the text content of an element (ignores HTML tags). javascript titleElement.textContent = "New Title!"; console.log(titleElement.textContent); // "New Title!" innerHTML : Gets or sets the HTML content of an element (parses HTML tags). javascript firstParagraph.innerHTML = "This is a <strong>bold</strong> paragraph."; setAttribute() : Sets the value of an attribute on the specified element. javascript button.setAttribute("id", "myButton"); removeAttribute() : Removes an attribute from an element. javascript // button.removeAttribute("id"); classList : Provides methods to add, remove, toggle, or check for CSS classes. javascript button.classList.add("btn-primary"); button.classList.remove("btn-secondary"); button.classList.toggle("active"); // Adds if not present, removes if present if (button.classList.contains("btn-primary")) { console.log("Button has btn-primary class."); } Styling Elements You can change the inline styles of elements using the style property. titleElement.style.color = "blue"; titleElement.style.fontSize = "40px"; titleElement.style.backgroundColor = "lightgray"; For more complex styling or when applying multiple styles, it's often better to toggle CSS classes.
Event Handling Events are actions or occurrences that happen in the browser, such as a user clicking a button, a page loading, or a key being pressed. JavaScript allows you to respond to these events. addEventListener() : The recommended way to attach event handlers. It allows multiple handlers for the same event on the same element. ```javascript button.addEventListener("click", function() { alert("Button clicked!"); }); // You can add multiple listeners button.addEventListener("click", () => { console.log("Another click handler."); }); ``` Event Object: When an event occurs, an Event object is passed to the event handler function. This object contains information about the event. javascript button.addEventListener("click", (event) => { console.log("Event type:", event.type); console.log("Target element:", event.target); }); Common Events: click : When an element is clicked. mouseover , mouseout : When the mouse pointer enters/leaves an element. keydown , keyup : When a key is pressed/released. submit : When a form is submitted. load : When a page or an image has finished loading. change : When the value of an input element changes. 7. ES6+ Features ECMAScript 2015 (ES6) marked a significant turning point in JavaScript development, introducing a plethora of new features that greatly improved the language's expressiveness, readability, and capabilities. Subsequent annual releases (ES2016,
ES2017, etc.) have continued to add valuable enhancements. Here are some of the most impactful ES6+ features: Template Literals Template literals (also known as template strings) provide a more flexible and readable way to create strings, especially when they involve variables or expressions. They are enclosed by backticks ( ` ) instead of single or double quotes. Multi-line Strings: Easily create strings that span multiple lines without using n . javascript const multiLine = ` This is a string that spans multiple lines. `; console.log(multiLine); Expression Interpolation: Embed expressions directly within the string using ${expression} . ``javascript const name = "World"; const greeting = Hello, ${name}!`; console.log(greeting); // "Hello, World!" const a = 10; const b = 5; console.log( The sum of $ and ${b} is ${a + b}. ); // "The sum of 10 and 5 is 15." ``` Classes Classes, introduced in ES6, are a syntactic sugar over JavaScript's existing prototype- based inheritance. They provide a cleaner and more familiar object-oriented syntax for creating objects and handling inheritance.
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 Doe", 30); console.log(john.greet()); // "Hello, my name is John Doe and I am 30 years old." // Inheritance class Student extends Person { constructor(name, age, studentId) { super(name, age); // Call the parent class constructor this.studentId = studentId; } study() { return `$`{this.name} (ID: `${this.studentId}) is studying.`; } } const alice = new Student("Alice Smith", 20, "S12345"); console.log(alice.greet()); // "Hello, my name is Alice Smith and I am 20 years old." console.log(alice.study()); // "Alice Smith (ID: S12345) is studying." Modules (Import/Export) ES6 modules provide a standardized way to organize JavaScript code into separate files, making it easier to manage dependencies, improve reusability, and prevent global namespace pollution. Modules use export to make variables, functions, or classes available to other files, and import to bring them into the current file. math.js (Exporting module): // math.js export const PI = 3.14159; export function add(a, b) { return a + b; } export default function subtract(a, b) { return a - b; }
app.js (Importing module): // app.js import { PI, add } from './math.js'; // Named imports import subtractAlias from './math.js'; // Default import (can be renamed) console.log(PI); // 3.14159 console.log(add(5, 2)); // 7 console.log(subtractAlias(10, 3)); // 7 // Import all as an object import * as MathFunctions from './math.js'; console.log(MathFunctions.PI); Iterators and Generators Iterators: An object is an iterator when it implements the next() method, which returns an object with two properties: value (the next value in the sequence) and done (a boolean indicating if the sequence has finished). Generators: Generator functions are a special type of function that can be paused and resumed, allowing them to produce a sequence of values over time. They are defined using function* and use the yield keyword to pause execution and return a value. ```javascript function* idGenerator() { let id = 1; while (true) { yield id++; } } const gen = idGenerator(); console.log(gen.next().value); // 1 console.log(gen.next().value); // 2 console.log(gen.next().value); // 3 ``` Map and Set ES6 introduced new built-in objects for storing collections of data, offering advantages over plain objects and arrays in certain scenarios. Map : A collection of key-value pairs where keys can be of any data type (unlike plain objects where keys are limited to strings or Symbols). Map maintains the insertion order of elements. ```javascript const myMap = new Map(); myMap.set("name", "Alice"); myMap.set(1, "one"); myMap.set(true, "boolean");
console.log(myMap.get("name")); // "Alice" console.log(myMap.has(1)); // true myMap.delete("name"); console.log(myMap.size); // 2 // Iterating over a Map for (const [key, value] of myMap) { console.log( $ : ${value} ); } ``` Set : A collection of unique values. Duplicate values are automatically ignored. Set maintains the insertion order of elements. ```javascript const mySet = new Set(); mySet.add(1); mySet.add("hello"); mySet.add(1); // This will be ignored console.log(mySet.has("hello")); // true mySet.delete(1); console.log(mySet.size); // 1 // Iterating over a Set for (const item of mySet) { console.log(item); } // Convert array to Set to get unique values const numbers = [1, 2, 2, 3, 4, 4, 5]; const uniqueNumbers = [...new Set(numbers)]; console.log(uniqueNumbers); // [1, 2, 3, 4, 5] ``` 8. Advanced Concepts Beyond the foundational elements and modern features, JavaScript encompasses several advanced concepts that are crucial for writing robust, efficient, and maintainable code. Understanding these concepts helps in debugging complex issues and mastering the language. this Keyword The this keyword in JavaScript is one of the most misunderstood concepts. Its value is determined by how a function is called, not where it is defined. The this context can change dynamically. Global Context: In the global execution context (outside of any function), this refers to the global object ( window in browsers, global in Node.js). javascript console.log(this === window); // true (in browser)
Function Context (Simple Function Call): In a regular function call, this also refers to the global object (or undefined in strict mode). javascript function showThis() { console.log(this); } showThis(); // window object (non-strict), undefined (strict) Method Context: When a function is called as a method of an object, this refers to the object that owns the method. javascript const person = { name: "Alice", greet: function() { console.log(`Hello, my name is ${this.name}`); } }; person.greet(); // "Hello, my name is Alice" Constructor Context: When a function is used as a constructor with the new keyword, this refers to the newly created instance of the object. javascript function Car(make) { this.make = make; } const myCar = new Car("Toyota"); console.log(myCar.make); // "Toyota" Explicit Binding ( call , apply , bind ): call() : Invokes the function with a specified this value and arguments provided individually. apply() : Invokes the function with a specified this value and arguments provided as an array. bind() : Returns a new function, allowing you to permanently set the this context. ```javascript const anotherPerson = { name: "Bob" }; function sayName() { console.log(this.name); } sayName.call(anotherPerson); // "Bob" sayName.apply(anotherPerson); // "Bob" const boundSayName = sayName.bind(anotherPerson); boundSayName(); // "Bob" ``` Arrow Functions and this : Arrow functions do not have their own this context. They inherit this from their lexical (enclosing) scope. This makes them
very useful in callbacks where you want to preserve the this context of the surrounding code. javascript const user = { name: "Charlie", logMessages: function() { setTimeout(() => { console.log(`Hello from ${this.name}`); // 'this' refers to 'user' }, 1000); } }; user.logMessages(); // "Hello from Charlie" (after 1 second) Prototypes and Prototypal Inheritance JavaScript is a prototype-based language, meaning that objects can inherit properties and methods directly from other objects. Every JavaScript object has a prototype, which is another object that it inherits properties and methods from. The prototype chain is how inheritance works in JavaScript. __proto__ and [[Prototype]] : Every object has an internal [[Prototype]] property, which points to its prototype object. This is often exposed via the __proto__ property (though Object.getPrototypeOf() is the standard way to access it). prototype property of functions: Functions in JavaScript also have a prototype property. When a function is used as a constructor (with new ), the prototype property of the constructor function becomes the [[Prototype]] of the newly created object. ```javascript function Vehicle(make) { this.make = make; } Vehicle.prototype.getMake = function() { return this.make; }; const car = new Vehicle("Honda"); console.log(car.getMake()); // "Honda" console.log(car.proto === Vehicle.prototype); // true console.log(Object.getPrototypeOf(car) === Vehicle.prototype); // true ``` Prototype Chain: When you try to access a property or method on an object, JavaScript first looks for it directly on the object. If it doesn't find it, it then looks on the object's prototype, then on the prototype's prototype, and so on, until it reaches null (the end of the chain). javascript // Example of prototype chain console.log(car.toString()); // Inherited from Object.prototype
console.log(car.__proto__.__proto__ === Object.prototype); // true Hoisting Hoisting is a JavaScript mechanism where variable and function declarations are moved to the top of their containing scope during the compilation phase, before code execution. This means you can use variables and functions before they are declared in your code. Function Hoisting: Function declarations are fully hoisted, meaning both the function name and its definition are moved to the top. So, you can call a function before its declaration. ```javascript hoistedFunction(); // "Hello from hoisted function!" function hoistedFunction() { console.log("Hello from hoisted function!"); } ``` Variable Hoisting ( var ): Variables declared with var are hoisted, but only their declaration is hoisted, not their initialization. This means they are initialized with undefined . javascript console.log(hoistedVar); // undefined var hoistedVar = "I am hoisted"; console.log(hoistedVar); // "I am hoisted" let and const (Temporal Dead Zone): Variables declared with let and const are also hoisted, but they are not initialized. They are in a "Temporal Dead Zone" (TDZ) from the beginning of the block until their declaration is processed. Accessing them before declaration will result in a ReferenceError . javascript // console.log(tdzVar); // ReferenceError: Cannot access 'tdzVar' before initialization let tdzVar = "I am in TDZ"; Event Delegation Event delegation is a technique where you attach a single event listener to a parent element, instead of attaching multiple event listeners to individual child elements. This single listener then listens for events bubbling up from its children. It's particularly useful for dynamically added elements or a large number of similar elements.
Benefits: * Performance: Reduces the number of event listeners, saving memory and improving performance. * Dynamic Elements: Automatically handles events for elements added to the DOM after the initial page load. * Simpler Code: Less code to write and maintain. <ul id="myList"> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> </ul> const myList = document.getElementById("myList"); myList.addEventListener("click", function(event) { // Check if the clicked element is an LI if (event.target.tagName === "LI") { console.log("Clicked on:", event.target.textContent); event.target.style.color = "red"; } }); // Dynamically add a new item const newItem = document.createElement("li"); newItem.textContent = "Item 4"; myList.appendChild(newItem); // Clicking on Item 4 will also work due to event delegation Error Handling (try...catch...finally) Error handling is crucial for creating robust applications. JavaScript provides the try...catch...finally statement to handle runtime errors gracefully. try block: Contains the code that might throw an error. catch block: Contains the code to be executed if an error occurs in the try block. It receives the error object as an argument. finally block: Contains code that will always be executed, regardless of whether an error occurred or not.
function divide(a, b) { try { if (b === 0) { throw new Error("Division by zero is not allowed."); } return a / b; } catch (error) { console.error("An error occurred:", error.message); return NaN; // Return Not a Number on error } finally { console.log("Division operation attempted."); } } console.log(divide(10, 2)); // Output: 5, then "Division operation attempted." console.log(divide(10, 0)); // Output: "An error occurred: Division by zero is not allowed.", then NaN, then "Division operation attempted." 9. Modern JavaScript Development Modern JavaScript development involves a rich ecosystem of tools and practices that streamline the development process, improve code quality, and enhance performance. These tools often work together to transform your source code into optimized, production-ready applications. Introduction to npm npm (Node Package Manager) is the default package manager for Node.js and the world's largest software registry. It allows developers to share and reuse code, making it incredibly easy to manage project dependencies and automate development tasks. Installing npm: npm is installed automatically when you install Node.js. package.json : This file is at the heart of any npm project. It stores metadata about the project (name, version, description) and lists all its dependencies ( dependencies for production, devDependencies for development-only tools). json { "name": "my-js-project", "version": "1.0.0", "description": "A simple JavaScript project", "main": "index.js", "scripts": { "start": "node index.js", "test": "echo "Error: no test specified" && exit 1" }, "keywords": [], "author": "Manus AI", "license": "ISC", "dependencies": { "axios": "^1.6.0" }, "devDependencies": { "eslint": "^8.56.0" } }
Common npm Commands: npm init : Initializes a new package.json file. npm install : Installs all dependencies listed in package.json . npm install <package-name> : Installs a specific package as a production dependency. npm install <package-name> --save-dev or npm install <package- name> -D : Installs a specific package as a development dependency. npm uninstall <package-name> : Uninstalls a package. npm update : Updates packages to their latest compatible versions. npm run <script-name> : Executes a script defined in the scripts section of package.json . Transpilers (Babel) JavaScript is constantly evolving, with new features being added regularly. However, not all browsers or Node.js environments support the latest features immediately. A transpiler (like Babel) converts modern JavaScript code (e.g., ES6+) into an older, backward-compatible version of JavaScript (e.g., ES5) that can run in a wider range of environments. How Babel Works: Babel takes your source code, parses it into an Abstract Syntax Tree (AST), transforms the AST based on configured plugins and presets, and then generates new code from the transformed AST. Presets: Collections of plugins that support a particular set of JavaScript features (e.g., @babel/preset-env for all modern JavaScript features). ``javascript // ES6+ source code const greet = (name) => Hello, ${name}!`; // Transpiled ES5 code (by Babel) var greet = function greet(name) { return "Hello, " + name + "!"; }; ```
Bundlers (Webpack, Parcel) As JavaScript applications grow, they often consist of many modules and assets (CSS, images, fonts). Bundlers are tools that combine these separate modules and assets into a single (or a few) optimized bundles for deployment. This reduces the number of HTTP requests a browser needs to make, improving load times. Webpack: A highly configurable and powerful module bundler. It can handle various asset types through loaders and plugins. Parcel: A zero-configuration bundler that aims for a faster and easier development experience. Key functions of bundlers: * Module Resolution: Understands import and require statements to build a dependency graph. * Transpilation: Integrates with transpilers like Babel to convert modern JavaScript. * Minification: Removes unnecessary characters (whitespace, comments) from code to reduce file size. * Code Splitting: Divides code into smaller chunks that can be loaded on demand, improving initial load performance. * Asset Management: Can process and optimize other assets like CSS, images, and fonts. Linting (ESLint) Linting is the process of analyzing source code to flag programming errors, bugs, stylistic errors, and suspicious constructs. Linters help enforce coding standards and identify potential problems early in the development cycle. ESLint: The most popular JavaScript linter. It is highly configurable and allows developers to define their own rules or use popular style guides (e.g., Airbnb, Standard). Benefits of Linting: * Code Quality: Catches common errors and anti-patterns. * Consistency: Ensures a consistent coding style across a team or project. * Early Detection: Identifies issues before they become harder to debug runtime errors. * Improved Readability: Consistent formatting and adherence to best practices make code easier to read and understand. Example ESLint rule:
// Bad (ESLint would flag this) var x = 10; // Good const x = 10; These tools collectively form the backbone of a modern JavaScript development workflow, enabling developers to build complex, high-quality, and performant applications efficiently. 10. Best Practices and Tips Writing good JavaScript code goes beyond just knowing the syntax and features. Adhering to best practices, optimizing for performance, and understanding debugging techniques are crucial for building maintainable, scalable, and robust applications. Clean Code Principles Clean code is code that is easy to read, understand, and modify. Following these principles improves collaboration and reduces technical debt. Meaningful Names: Use descriptive names for variables, functions, and classes that clearly indicate their purpose. Avoid single-letter names or abbreviations unless they are universally understood (e.g., i for loop counters). ```javascript // Bad let d = new Date(); let val = calculate(x, y); // Good let currentDate = new Date(); let totalAmount = calculateTotalPrice(itemPrice, quantity); ``` Small Functions: Functions should do one thing and do it well. Keep functions short and focused, ideally no more than 20-30 lines of code. Avoid Global Variables: Minimize the use of global variables to prevent naming collisions and make code more modular. Use modules, closures, or IIFEs to encapsulate variables. Comments: Write comments that explain why the code does something, not what it does (the code itself should be self-explanatory). Remove commented- out code.
Consistency: Maintain a consistent coding style (indentation, naming conventions, semicolon usage) across your entire codebase. Linters like ESLint can help enforce this. DRY (Don't Repeat Yourself): Avoid duplicating code. If you find yourself writing the same logic multiple times, extract it into a reusable function or module. Performance Optimization Optimizing JavaScript code ensures that your applications run smoothly and efficiently, providing a better user experience. Minimize DOM Manipulation: DOM operations are expensive. Batch changes, use document fragments, or update innerHTML once instead of multiple times. Avoid Layout Thrashing: Repeatedly reading and writing to the DOM can cause the browser to recalculate layout multiple times. Read all necessary layout properties first, then perform all writes. Optimize Loops: For large arrays, prefer for loops over forEach or map if performance is critical, as native loops can be faster. Cache array.length in for loops. javascript // Good for (let i = 0, len = arr.length; i < len; i++) { // ... } Debouncing and Throttling: For events that fire frequently (e.g., resize , scroll , mousemove , input ), use debouncing or throttling to limit the rate at which event handlers are executed. Lazy Loading: Load resources (images, components, modules) only when they are needed, reducing initial load time. Use const and let : Prefer const and let over var to improve scope management and prevent accidental reassignments, which can sometimes lead to minor performance benefits due to better optimization by JavaScript engines.
Debugging Techniques Debugging is an essential skill for every developer. Modern browsers provide powerful developer tools to help you find and fix issues. console.log() : The simplest and most common debugging tool. Use console.log() , console.warn() , console.error() , console.table() , console.dir() to inspect values and program flow. Browser Developer Tools: Elements Tab: Inspect and modify HTML and CSS. Console Tab: View logs, errors, and execute JavaScript code. Sources Tab: Set breakpoints, step through code, inspect variables, and modify code on the fly. Network Tab: Monitor network requests and responses. Performance Tab: Analyze runtime performance. Memory Tab: Profile memory usage. Breakpoints: Pause code execution at specific lines to inspect the state of variables and the call stack. debugger keyword: Insert debugger; into your code to programmatically set a breakpoint. When the developer tools are open, execution will pause at this point. Error Messages: Pay close attention to error messages in the console. They often provide valuable clues about the type and location of the problem. Common Pitfalls and How to Avoid Them Loose Equality ( == ) vs. Strict Equality ( === ): Always use === (strict equality) to compare values, as == performs type coercion, which can lead to unexpected results. javascript console.log(0 == false); // true console.log(0 === false); // false console.log("5" == 5); // true console.log("5" === 5); // false
Floating Point Inaccuracy: JavaScript numbers are 64-bit floating-point. This can lead to precision issues with decimal numbers. Avoid direct comparison of floating-point numbers. javascript console.log(0.1 + 0.2 === 0.3); // false this Context Issues: As discussed, this can be tricky. Be mindful of how functions are called and use arrow functions or bind / call / apply to control this when necessary. Asynchronous Code Complexity: Callback hell, unhandled promises, and race conditions are common. Use Promises and async/await to manage asynchronous flow effectively. Modifying Arrays While Iterating: Avoid adding or removing elements from an array while iterating over it with for...of or forEach , as this can lead to skipped elements or infinite loops. Iterate over a copy or use methods like filter or map to create new arrays. Global Scope Pollution: Declare variables within the narrowest possible scope to avoid unintended side effects and conflicts. By understanding and applying these best practices, you can write more efficient, readable, and maintainable JavaScript code, leading to more robust and successful applications.

Complete JavaScript Notes: From Basics to Advanced Concepts.pdf

  • 1.
    Complete JavaScript Notes 1.Introduction to JavaScript JavaScript is a versatile and powerful programming language primarily known for its role in web development. It enables interactive and dynamic content on websites, making them more engaging and user-friendly. Beyond web browsers, JavaScript has expanded its reach to various other domains, including server-side development with Node.js, mobile app development with frameworks like React Native, and even desktop applications. What is JavaScript? JavaScript is a high-level, interpreted programming language that conforms to the ECMAScript specification. It is a multi-paradigm language, supporting event-driven, functional, and imperative programming styles. Unlike compiled languages, JavaScript code is executed directly by an interpreter, typically within a web browser's JavaScript engine or a Node.js runtime environment. History and Evolution JavaScript was created in 1995 by Brendan Eich while he was working at Netscape Communications. Initially named LiveScript, it was quickly renamed JavaScript to capitalize on the popularity of Java at the time, despite having little to no direct relation to the Java programming language. The language was standardized under ECMAScript in 1997, and subsequent versions have introduced significant enhancements and new features, such as ES6 (ECMAScript 2015), which brought major improvements like arrow functions, classes, and modules. Where is JavaScript used? JavaScript's primary domain remains web development, where it powers the client- side interactivity of millions of websites. However, its applications have diversified considerably:
  • 2.
    Front-end Web Development:Used with HTML and CSS to create dynamic and interactive user interfaces. Frameworks and libraries like React, Angular, and Vue.js are built on JavaScript. Back-end Web Development: With Node.js, JavaScript can be used to build scalable and high-performance server-side applications, APIs, and microservices. Mobile App Development: Frameworks such as React Native and NativeScript allow developers to build cross-platform mobile applications using JavaScript. Desktop App Development: Electron and NW.js enable the creation of desktop applications using web technologies (HTML, CSS, JavaScript). Game Development: JavaScript can be used to develop browser-based games and even more complex games with libraries like Phaser. IoT (Internet of Things): JavaScript can be used to program various IoT devices. Setting up your development environment To start writing and running JavaScript code, you primarily need a text editor and a web browser. For more advanced development, a dedicated Integrated Development Environment (IDE) and Node.js are recommended. 1. Text Editor/IDE: Popular choices include Visual Studio Code, Sublime Text, Atom, or WebStorm. These provide features like syntax highlighting, autocompletion, and debugging tools. 2. Web Browser: Modern web browsers (Chrome, Firefox, Edge, Safari) come with built-in JavaScript engines and developer tools (console, debugger) that are essential for testing and debugging client-side JavaScript. 3. Node.js: For server-side JavaScript development and to use JavaScript outside the browser, install Node.js. It includes the npm (Node Package Manager) which is crucial for managing project dependencies and running development tools. 2. JavaScript Basics JavaScript's fundamental building blocks include variables, data types, operators, and control flow statements. Understanding these concepts is crucial for writing any JavaScript program.
  • 3.
    Variables (var, let,const) Variables are containers for storing data values. JavaScript provides three keywords to declare variables: var : Historically used for variable declaration. var declarations are function- scoped and are hoisted to the top of their function or global scope. This can lead to unexpected behavior, especially in loops or conditional blocks. javascript var x = 10; if (true) { var x = 20; // Same variable x console.log(x); // 20 } console.log(x); // 20 let : Introduced in ES6 (ECMAScript 2015), let declarations are block-scoped. This means the variable is only accessible within the block (e.g., if statement, for loop) where it is defined. javascript let y = 10; if (true) { let y = 20; // Different variable y console.log(y); // 20 } console.log(y); // 10 const : Also introduced in ES6, const is used to declare constants. Like let , const declarations are block-scoped. Once a const variable is assigned a value, it cannot be reassigned. However, for objects and arrays declared with const , their properties or elements can still be modified. ```javascript const PI = 3.14; // PI = 3.14159; // This would cause an error const person = { name: "Alice" }; person.name = "Bob"; // This is allowed console.log(person.name); // Bob ``` Data Types (Primitive and Non-Primitive) JavaScript has several built-in data types. They are broadly categorized into primitive and non-primitive (or reference) types. Primitive Data Types: String : Represents textual data. Enclosed in single quotes ( '...' ), double quotes (` "..." ), or backticks ( `...` for template literals). javascript let name = "John Doe"; * Number : Represents both integer and floating-point numbers. javascript
  • 4.
    let age =30; let price = 99.99; * Boolean : Represents a logical entity and can have two values: true or false . javascript let isActive = true; * Undefined : Represents a variable that has been declared but has not yet been assigned a value. javascript let city; // city is undefined * Null : Represents the intentional absence of any object value. It is a primitive value. javascript let car = null; * Symbol : (ES6) Represents a unique identifier. Used to create unique property keys that won't clash with other property keys. javascript const id = Symbol('id'); * BigInt : (ES2020) Represents whole numbers larger than 2^53 - 1, which is the largest number JavaScript can reliably represent with the Number primitive. javascript const bigNumber = 1234567890123456789012345678901234567890n; Non-Primitive (Reference) Data Types: Object : A collection of key-value pairs. Objects are the most fundamental non- primitive data type. javascript let person = { firstName: "John", lastName: "Doe" }; Array : A special type of object used to store ordered collections of data. javascript let colors = ["red", "green", "blue"]; Function : A block of code designed to perform a particular task. Functions are also objects in JavaScript. javascript function greet(name) { return "Hello, " + name; } Operators (Arithmetic, Assignment, Comparison, Logical, etc.) Operators are symbols that perform operations on operands (values and variables). Arithmetic Operators: Perform mathematical calculations.
  • 5.
    Operator Description Example +Addition x + y - Subtraction x - y * Multiplication x * y / Division x / y % Modulus x % y ** Exponentiation x ** y ++ Increment x++ or ++x -- Decrement x-- or --x Assignment Operators: Assign values to variables. Operator Example Same As = x = y x = y += x += y x = x + y -= x -= y x = x - y *= x *= y x = x * y /= x /= y x = x / y %= x %= y x = x % y **= x **= y x = x ** y Comparison Operators: Compare two values and return a boolean result.
  • 6.
    Operator Description Example ==Equal to (loose equality) x == y === Equal value and type (strict equality) x === y != Not equal (loose inequality) x != y !== Not equal value or type (strict inequality) x !== y > Greater than x > y < Less than x < y >= Greater than or equal to x >= y <= Less than or equal to x <= y Logical Operators: Combine conditional statements. Operator Description Example && Logical AND x < 10 && x > 5 || Logical OR x < 5 || x > 10 ! Logical NOT !(x === 5) Type Conversion (Implicit and Explicit) JavaScript is a loosely typed language, meaning variables do not have a fixed type. Values can be converted from one type to another, either implicitly (coercion) or explicitly. Implicit Type Conversion (Coercion): JavaScript automatically converts data types when an operation involves different types. javascript console.log("5" + 5); // "55" (Number 5 is converted to String "5") console.log("5" - 5); // 0 (String "5" is converted to Number 5) console.log(true + 1); // 2 (Boolean true is converted to Number 1)
  • 7.
    Explicit Type Conversion:Developers explicitly convert data types using built-in functions or methods. javascript console.log(Number("10")); // 10 console.log(String(100)); // "100" console.log(Boolean(0)); // false Conditional Statements (if, else if, else, switch) Conditional statements execute different actions based on different conditions. if , else if , else : javascript let hour = 14; if (hour < 12) { console.log("Good morning!"); } else if (hour < 18) { console.log("Good afternoon!"); } else { console.log("Good evening!"); } switch : Used to perform different actions based on different conditions. javascript let day = "Monday"; switch (day) { case "Monday": console.log("It's Monday."); break; case "Friday": console.log("It's Friday!"); break; default: console.log("It's another day."); } Loops (for, while, do-while, for...in, for...of) Loops are used to execute a block of code repeatedly. for loop: Iterates a block of code a number of times. javascript for (let i = 0; i < 5; i++) { console.log(i); } while loop: Executes a block of code as long as a specified condition is true. javascript let i = 0; while (i < 5) { console.log(i); i++; } do...while loop: Similar to while , but the block of code is executed at least once before the condition is tested. javascript let i = 0; do { console.log(i); i++; } while (i < 5); for...in loop: Iterates over the enumerable properties of an object.
  • 8.
    javascript const person= { fname: "John", lname: "Doe", age: 25 }; for (let x in person) { console.log(x + ": " + person[x]); } for...of loop: (ES6) Iterates over iterable objects (like Arrays, Strings, Maps, Sets, etc.). javascript const colors = ["red", "green", "blue"]; for (let color of colors) { console.log(color); } 3. Functions Functions are fundamental building blocks in JavaScript. They are reusable blocks of code that perform a specific task. Functions allow you to organize your code, make it more modular, and avoid repetition (DRY - Don't Repeat Yourself principle). Function Declaration and Expression There are two primary ways to define functions in JavaScript: Function Declaration (or Function Statement): This is the most common way to define a function. Function declarations are hoisted, meaning they can be called before they are defined in the code. ```javascript // Function Declaration function greet(name) { return "Hello, " + name + "!"; } console.log(greet("Alice")); // Output: Hello, Alice! ``` Function Expression: A function expression defines a function as part of an expression, typically assigned to a variable. Function expressions are not hoisted, so they cannot be called before they are defined. ```javascript // Function Expression const sayHello = function(name) { return "Hello, " + name + "!"; }; console.log(sayHello("Bob")); // Output: Hello, Bob! // console.log(anotherGreet("Charlie")); // This would cause an error if called before definition ```
  • 9.
    Arrow Functions Arrow functions(introduced in ES6) provide a more concise syntax for writing function expressions. They also behave differently regarding the this keyword (which will be discussed in a later section). Basic Syntax: javascript const add = (a, b) => a + b; console.log(add(5, 3)); // Output: 8 Single Parameter: Parentheses are optional for a single parameter. javascript const square = num => num * num; console.log(square(4)); // Output: 16 No Parameters: Empty parentheses are required. javascript const sayHi = () => "Hi there!"; console.log(sayHi()); // Output: Hi there! Block Body: For multiple statements, use curly braces and a return statement. javascript const calculateArea = (length, width) => { const area = length * width; return `The area is ${area} square units.`; }; console.log(calculateArea(10, 5)); // Output: The area is 50 square units. Parameters and Arguments Parameters: Named variables listed in the function definition. They act as placeholders for the values that will be passed into the function. Arguments: The actual values passed to the function when it is called. ```javascript function multiply(a, b) { // a and b are parameters return a * b; } console.log(multiply(7, 2)); // 7 and 2 are arguments ```
  • 10.
    Return Values Functions canreturn a value using the return statement. If no return statement is specified, or if return; is used without a value, the function implicitly returns undefined . function getMax(x, y) { if (x > y) { return x; } else { return y; } } let result = getMax(15, 8); console.log(result); // Output: 15 function doNothing() { // No return statement } console.log(doNothing()); // Output: undefined Scope (Global, Local, Block) Scope determines the accessibility of variables, objects, and functions in different parts of your code. Global Scope: Variables declared outside any function or block have global scope. They can be accessed from anywhere in the code. ```javascript let globalVar = "I am global"; function accessGlobal() { console.log(globalVar); } accessGlobal(); // Output: I am global ``` Function (Local) Scope: Variables declared inside a function (using var , let , or const ) are function-scoped. They are only accessible within that function. javascript function localScopeExample() { var localVar = "I am local (var)"; let anotherLocalVar = "I am local (let)"; const PI = 3.14; // Also local console.log(localVar); console.log(anotherLocalVar); } localScopeExample(); // console.log(localVar); // Error: localVar is not defined
  • 11.
    Block Scope: Variablesdeclared with let and const inside a block (e.g., if statement, for loop, or any {} block) are block-scoped. They are only accessible within that block. javascript if (true) { let blockVar = "I am block-scoped"; console.log(blockVar); // Output: I am block-scoped } // console.log(blockVar); // Error: blockVar is not defined Closures A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In simpler terms, a closure gives you access to an outer function's scope from an inner function, even after the outer function has finished executing. function outerFunction(outerVariable) { return function innerFunction(innerVariable) { console.log("Outer Variable: " + outerVariable); console.log("Inner Variable: " + innerVariable); }; } const newFunction = outerFunction("Hello"); newFunction("World"); // Output: // Outer Variable: Hello // Inner Variable: World // Even after outerFunction has returned, innerFunction still has access to outerVariable Closures are powerful for creating private variables and functions, and for implementing patterns like currying and memoization. Immediately Invoked Function Expressions (IIFE) An IIFE is a JavaScript function that runs as soon as it is defined. It's a design pattern that creates a private scope for variables, preventing them from polluting the global namespace.
  • 12.
    (function() { var privateVar= "I am private"; console.log(privateVar); })(); // The function is immediately invoked // console.log(privateVar); // Error: privateVar is not defined // IIFE with parameters (function(message) { console.log(message); })("This is an IIFE with a parameter."); IIFEs are commonly used in older JavaScript codebases to encapsulate modules and prevent variable collisions. 4. Objects and Arrays Objects and Arrays are fundamental data structures in JavaScript, used for storing collections of data. They are both types of objects, but serve different purposes and have distinct characteristics. Objects (Creation, Properties, Methods) An object in JavaScript is a standalone entity, with properties and type. Objects are collections of key-value pairs. The keys (or property names) are strings (or Symbols), and the values can be any data type, including other objects, functions, or primitive values. Creation of Objects: 1. Object Literal (Recommended for simple objects): The simplest way to create an object. javascript const person = { firstName: "John", lastName: "Doe", age: 30, isStudent: false, // A method (function as a property) greet: function() { return `Hello, my name is $`{this.firstName} `${this.lastName}.`; } }; 2. new Object() (Less common): javascript const car = new Object(); car.make = "Toyota"; car.model = "Camry";
  • 13.
    3. Constructor Function:Used to create multiple objects of the same type. ``javascript function Book(title, author, year) { this.title = title; this.author = author; this.year = year; this.getSummary = function() { return $ {this.title} by ${this.author}, published in ${this.year}.`; }; } const book1 = new Book("The Hobbit", "J.R.R. Tolkien", 1937); console.log(book1.getSummary()); ``` 4. class Keyword (ES6): Syntactic sugar over constructor functions and prototypes. ```javascript class Animal { constructor(name, species) { this.name = name; this.species = species; } makeSound() { console.log("Generic animal sound"); } } const dog = new Animal("Buddy", "Dog"); dog.makeSound(); ``` Accessing Properties: Dot Notation (Recommended): javascript console.log(person.firstName); // "John" Bracket Notation (Useful for dynamic property names or properties with special characters): javascript console.log(person["lastName"]); // "Doe" let prop = "age"; console.log(person[prop]); // 30 Modifying Properties: person.age = 31; person["isStudent"] = true; console.log(person.age); // 31 console.log(person.isStudent); // true Adding New Properties:
  • 14.
    person.nationality = "American"; console.log(person.nationality);// "American" Deleting Properties: delete person.isStudent; console.log(person.isStudent); // undefined Methods: Functions stored as object properties. console.log(person.greet()); // "Hello, my name is John Doe." Arrays (Creation, Methods, Iteration) Arrays are ordered collections of values. Each value is called an element, and each element has a numeric position called an index (starting from 0). Creation of Arrays: 1. Array Literal (Recommended): javascript const fruits = ["apple", "banana", "cherry"]; const numbers = [1, 2, 3, 4, 5]; const mixed = ["text", 123, true, { key: "value" }]; 2. new Array() (Less common): javascript const emptyArray = new Array(); const fiveElements = new Array(5); // Creates an array with 5 empty slots const colors = new Array("red", "green", "blue"); Accessing Elements: Elements are accessed using their index in bracket notation. console.log(fruits[0]); // "apple" console.log(fruits[2]); // "cherry" console.log(fruits.length); // 3 Modifying Elements:
  • 15.
    fruits[1] = "grape"; console.log(fruits);// ["apple", "grape", "cherry"] Common Array Methods: JavaScript provides a rich set of built-in methods for manipulating arrays.
  • 16.
    Method Description Example push() Addsone or more elements to the end of an array and returns the new length. arr.push("new") pop() Removes the last element from an array and returns that element. arr.pop() shift() Removes the first element from an array and returns that element. arr.shift() unshift() Adds one or more elements to the beginning of an array and returns the new length. arr.unshift("first") splice() Changes the contents of an array by removing or replacing existing elements and/or adding new elements in place. arr.splice(index, deleteCount, item1, ...) slice() Returns a shallow copy of a portion of an array into a new array object. arr.slice(startIndex, endIndex) concat() Used to merge two or more arrays. arr1.concat(arr2) indexOf() Returns the first index at which a given element can be found in the array, or -1 if it is not present. arr.indexOf("item") includes() Determines whether an array includes a certain value among its entries, returning true or false as appropriate. arr.includes("item") forEach() Executes a provided function once for each array element. arr.forEach(callback) map() Creates a new array populated with the results of calling a provided function on every element in the calling array. arr.map(callback) filter() Creates a new array with all elements that pass the test implemented by the provided function. arr.filter(callback)
  • 17.
    Method Description Example reduce() Executesa reducer function (that you provide) on each element of the array, resulting in single output value. arr.reduce(callback, initialValue) find() Returns the value of the first element in the provided array that satisfies the provided testing function. arr.find(callback) sort() Sorts the elements of an array in place and returns the sorted array. arr.sort() reverse() Reverses an array in place. arr.reverse() Iteration over Arrays: for loop: javascript for (let i = 0; i < fruits.length; i++) { console.log(fruits[i]); } forEach() method: javascript fruits.forEach(function(fruit, index) { console.log(`$`{index}: `${fruit}`); }); for...of loop (ES6): javascript for (const fruit of fruits) { console.log(fruit); } Destructuring (Object and Array) Destructuring assignment is a special syntax that allows you to unpack values from arrays, or properties from objects, into distinct variables. Object Destructuring: ```javascript const person = { name: "Alice", age: 25, city: "New York" }; const { name, age } = person; console.log(name); // "Alice" console.log(age); // 25
  • 18.
    // Renaming variablesconst { name: personName, city: personCity } = person; console.log(personName); // "Alice" console.log(personCity); // "New York" ``` Array Destructuring: ```javascript const colors = ["red", "green", "blue"]; const [firstColor, secondColor] = colors; console.log(firstColor); // "red" console.log(secondColor); // "green" // Skipping elements const [,, thirdColor] = colors; console.log(thirdColor); // "blue" // With rest operator const [primary, ...restColors] = colors; console.log(primary); // "red" console.log(restColors); // ["green", "blue"] ``` Spread and Rest Operators Both the spread ( ... ) and rest ( ... ) operators use the same syntax but serve different purposes based on where they are used. Spread Operator ( ... ): Expands an iterable (like an array or string) into individual elements. Useful for copying arrays, merging arrays, or passing multiple arguments to a function. ```javascript // Copying an array const originalArray = [1, 2, 3]; const copiedArray = [...originalArray]; // [1, 2, 3] // Merging arrays const arr1 = [1, 2]; const arr2 = [3, 4]; const mergedArray = [...arr1, ...arr2]; // [1, 2, 3, 4] // Spreading properties in objects (ES2018) const obj1 = { a: 1, b: 2 }; const obj2 = { c: 3, d: 4 }; const mergedObject = { ...obj1, ...obj2 }; // { a: 1, b: 2, c: 3, d: 4 } // Passing arguments to a function function sum(a, b, c) { return a + b + c; } const nums = [1, 2, 3]; console.log(sum(...nums)); // 6 ``` Rest Operator ( ... ): Collects multiple elements into an array. Used in function parameters to handle an indefinite number of arguments, or in destructuring assignments. ```javascript // In function parameters function collectArgs(firstArg, ...restArgs) { console.log(firstArg); // "A" console.log(restArgs); // ["B", "C", "D"] }
  • 19.
    collectArgs("A", "B", "C","D"); // In array destructuring (as shown above) const [head, ...tail] = [1, 2, 3, 4]; console.log(head); // 1 console.log(tail); // [2, 3, 4] ``` 5. Asynchronous JavaScript JavaScript is a single-threaded language, meaning it can only execute one task at a time. However, many operations, such as fetching data from a server, reading a file, or waiting for a user action, can take time. If these operations were synchronous (blocking), the entire application would freeze until they completed. Asynchronous programming allows JavaScript to handle these long-running tasks without blocking the main thread, ensuring a smooth and responsive user experience. Callbacks A callback 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. This is the traditional way of handling asynchronous operations in JavaScript. function fetchData(callback) { // Simulate a network request setTimeout(() => { const data = { message: "Data fetched successfully!" }; callback(null, data); // Pass null for error, and data on success }, 2000); } console.log("Fetching data..."); fetchData((error, data) => { if (error) { console.error("Error:", error); } else { console.log(data.message); } }); console.log("This will be logged before the data is fetched."); Callback Hell (Pyramid of Doom): When multiple asynchronous operations depend on each other, you can end up with nested callbacks, which makes the code hard to read and maintain. This is known as "callback hell."
  • 20.
    Promises (States, Chaining,Error Handling) Promises, introduced in ES6, provide a cleaner and more robust way to handle asynchronous operations. A Promise is an object representing the eventual completion (or failure) of an asynchronous operation and its resulting value. Promise States: pending : Initial state, neither fulfilled nor rejected. fulfilled : The operation completed successfully. rejected : The operation failed. Creating a Promise: const myPromise = new Promise((resolve, reject) => { // Asynchronous operation setTimeout(() => { const success = true; if (success) { resolve("Promise resolved!"); } else { reject("Promise rejected!"); } }, 2000); }); Consuming a Promise: myPromise .then(result => { console.log(result); // "Promise resolved!" }) .catch(error => { console.error(error); // "Promise rejected!" }) .finally(() => { console.log("Promise finished."); }); Promise Chaining: Promises can be chained together to handle a sequence of asynchronous operations.
  • 21.
    fetch('https://api.example.com/data') .then(response => response.json())// .json() also returns a promise .then(data => { console.log(data); }) .catch(error => { console.error('Error fetching data:', error); }); Async/Await async/await , introduced in ES2017, is syntactic sugar built on top of Promises. It allows you to write asynchronous code that looks and behaves more like synchronous code, making it easier to read and reason about. async function: A function declared with the async keyword automatically returns a Promise . await operator: The await operator is used to wait for a Promise to resolve. It can only be used inside an async function. async function fetchDataAsync() { try { console.log("Fetching data..."); const response = await fetch('https://api.example.com/data'); const data = await response.json(); console.log(data); } catch (error) { console.error('Error:', error); } } fetchDataAsync(); Event Loop The Event Loop is the mechanism that allows JavaScript to perform non-blocking asynchronous operations, despite being single-threaded. It continuously checks the message queue for new messages (tasks) and executes them. 1. Call Stack: Where function calls are pushed and popped. 2. Web APIs (Browser) / C++ APIs (Node.js): Handle asynchronous operations (e.g., setTimeout , fetch ).
  • 22.
    3. Message Queue(or Task Queue): Where callback functions are placed after the asynchronous operation is complete. 4. Event Loop: When the Call Stack is empty, the Event Loop takes the first message from the Message Queue and pushes it onto the Call Stack for execution. This model ensures that the main thread is not blocked by long-running operations, allowing the user interface to remain responsive. 6. DOM Manipulation The Document Object Model (DOM) is a programming interface for web documents. It represents the page structure as a tree of objects, where each object corresponds to a part of the document, such as an element, attribute, or text. JavaScript can interact with this DOM tree to dynamically change the content, structure, and style of a web page. What is the DOM? When a web page is loaded, the browser creates a DOM of the page. The DOM is a platform- and language-neutral interface that allows programs and scripts to dynamically access and update the content, structure, and style of documents. It represents the document as nodes and objects. For example, consider this simple HTML: <!DOCTYPE html> <html> <head> <title>My Page</title> </head> <body> <h1 id="main-title">Hello, DOM!</h1> <p class="intro">This is a paragraph.</p> <button>Click Me</button> </body> </html> The DOM represents this as a tree structure, where document is the root, html is its child, and so on.
  • 23.
    Selecting Elements To manipulateelements, you first need to select them. JavaScript provides several methods for this: document.getElementById() : Selects a single element by its id attribute. Returns null if the element is not found. javascript const titleElement = document.getElementById("main- title"); console.log(titleElement.textContent); // "Hello, DOM!" document.getElementsByClassName() : Selects all elements with a specific class name. Returns an HTMLCollection (live collection). javascript const introParagraphs = document.getElementsByClassName("intro"); console.log(introParagraphs[0].textContent); // "This is a paragraph." document.getElementsByTagName() : Selects all elements with a specific tag name. Returns an HTMLCollection. javascript const allParagraphs = document.getElementsByTagName("p"); console.log(allParagraphs.length); // 1 document.querySelector() : Selects the first element that matches a specified CSS selector. This is a very versatile method. javascript const firstParagraph = document.querySelector("p.intro"); console.log(firstParagraph.textContent); // "This is a paragraph." const button = document.querySelector("button"); document.querySelectorAll() : Selects all elements that match a specified CSS selector. Returns a NodeList (static collection). javascript const allElements = document.querySelectorAll("h1, p"); allElements.forEach(el => console.log(el.tagName)); // H1, P
  • 24.
    Modifying HTML Contentand Attributes Once you have selected an element, you can modify its content and attributes. textContent : Gets or sets the text content of an element (ignores HTML tags). javascript titleElement.textContent = "New Title!"; console.log(titleElement.textContent); // "New Title!" innerHTML : Gets or sets the HTML content of an element (parses HTML tags). javascript firstParagraph.innerHTML = "This is a <strong>bold</strong> paragraph."; setAttribute() : Sets the value of an attribute on the specified element. javascript button.setAttribute("id", "myButton"); removeAttribute() : Removes an attribute from an element. javascript // button.removeAttribute("id"); classList : Provides methods to add, remove, toggle, or check for CSS classes. javascript button.classList.add("btn-primary"); button.classList.remove("btn-secondary"); button.classList.toggle("active"); // Adds if not present, removes if present if (button.classList.contains("btn-primary")) { console.log("Button has btn-primary class."); } Styling Elements You can change the inline styles of elements using the style property. titleElement.style.color = "blue"; titleElement.style.fontSize = "40px"; titleElement.style.backgroundColor = "lightgray"; For more complex styling or when applying multiple styles, it's often better to toggle CSS classes.
  • 25.
    Event Handling Events areactions or occurrences that happen in the browser, such as a user clicking a button, a page loading, or a key being pressed. JavaScript allows you to respond to these events. addEventListener() : The recommended way to attach event handlers. It allows multiple handlers for the same event on the same element. ```javascript button.addEventListener("click", function() { alert("Button clicked!"); }); // You can add multiple listeners button.addEventListener("click", () => { console.log("Another click handler."); }); ``` Event Object: When an event occurs, an Event object is passed to the event handler function. This object contains information about the event. javascript button.addEventListener("click", (event) => { console.log("Event type:", event.type); console.log("Target element:", event.target); }); Common Events: click : When an element is clicked. mouseover , mouseout : When the mouse pointer enters/leaves an element. keydown , keyup : When a key is pressed/released. submit : When a form is submitted. load : When a page or an image has finished loading. change : When the value of an input element changes. 7. ES6+ Features ECMAScript 2015 (ES6) marked a significant turning point in JavaScript development, introducing a plethora of new features that greatly improved the language's expressiveness, readability, and capabilities. Subsequent annual releases (ES2016,
  • 26.
    ES2017, etc.) havecontinued to add valuable enhancements. Here are some of the most impactful ES6+ features: Template Literals Template literals (also known as template strings) provide a more flexible and readable way to create strings, especially when they involve variables or expressions. They are enclosed by backticks ( ` ) instead of single or double quotes. Multi-line Strings: Easily create strings that span multiple lines without using n . javascript const multiLine = ` This is a string that spans multiple lines. `; console.log(multiLine); Expression Interpolation: Embed expressions directly within the string using ${expression} . ``javascript const name = "World"; const greeting = Hello, ${name}!`; console.log(greeting); // "Hello, World!" const a = 10; const b = 5; console.log( The sum of $ and ${b} is ${a + b}. ); // "The sum of 10 and 5 is 15." ``` Classes Classes, introduced in ES6, are a syntactic sugar over JavaScript's existing prototype- based inheritance. They provide a cleaner and more familiar object-oriented syntax for creating objects and handling inheritance.
  • 27.
    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 Doe", 30); console.log(john.greet()); // "Hello, my name is John Doe and I am 30 years old." // Inheritance class Student extends Person { constructor(name, age, studentId) { super(name, age); // Call the parent class constructor this.studentId = studentId; } study() { return `$`{this.name} (ID: `${this.studentId}) is studying.`; } } const alice = new Student("Alice Smith", 20, "S12345"); console.log(alice.greet()); // "Hello, my name is Alice Smith and I am 20 years old." console.log(alice.study()); // "Alice Smith (ID: S12345) is studying." Modules (Import/Export) ES6 modules provide a standardized way to organize JavaScript code into separate files, making it easier to manage dependencies, improve reusability, and prevent global namespace pollution. Modules use export to make variables, functions, or classes available to other files, and import to bring them into the current file. math.js (Exporting module): // math.js export const PI = 3.14159; export function add(a, b) { return a + b; } export default function subtract(a, b) { return a - b; }
  • 28.
    app.js (Importing module): //app.js import { PI, add } from './math.js'; // Named imports import subtractAlias from './math.js'; // Default import (can be renamed) console.log(PI); // 3.14159 console.log(add(5, 2)); // 7 console.log(subtractAlias(10, 3)); // 7 // Import all as an object import * as MathFunctions from './math.js'; console.log(MathFunctions.PI); Iterators and Generators Iterators: An object is an iterator when it implements the next() method, which returns an object with two properties: value (the next value in the sequence) and done (a boolean indicating if the sequence has finished). Generators: Generator functions are a special type of function that can be paused and resumed, allowing them to produce a sequence of values over time. They are defined using function* and use the yield keyword to pause execution and return a value. ```javascript function* idGenerator() { let id = 1; while (true) { yield id++; } } const gen = idGenerator(); console.log(gen.next().value); // 1 console.log(gen.next().value); // 2 console.log(gen.next().value); // 3 ``` Map and Set ES6 introduced new built-in objects for storing collections of data, offering advantages over plain objects and arrays in certain scenarios. Map : A collection of key-value pairs where keys can be of any data type (unlike plain objects where keys are limited to strings or Symbols). Map maintains the insertion order of elements. ```javascript const myMap = new Map(); myMap.set("name", "Alice"); myMap.set(1, "one"); myMap.set(true, "boolean");
  • 29.
    console.log(myMap.get("name")); // "Alice"console.log(myMap.has(1)); // true myMap.delete("name"); console.log(myMap.size); // 2 // Iterating over a Map for (const [key, value] of myMap) { console.log( $ : ${value} ); } ``` Set : A collection of unique values. Duplicate values are automatically ignored. Set maintains the insertion order of elements. ```javascript const mySet = new Set(); mySet.add(1); mySet.add("hello"); mySet.add(1); // This will be ignored console.log(mySet.has("hello")); // true mySet.delete(1); console.log(mySet.size); // 1 // Iterating over a Set for (const item of mySet) { console.log(item); } // Convert array to Set to get unique values const numbers = [1, 2, 2, 3, 4, 4, 5]; const uniqueNumbers = [...new Set(numbers)]; console.log(uniqueNumbers); // [1, 2, 3, 4, 5] ``` 8. Advanced Concepts Beyond the foundational elements and modern features, JavaScript encompasses several advanced concepts that are crucial for writing robust, efficient, and maintainable code. Understanding these concepts helps in debugging complex issues and mastering the language. this Keyword The this keyword in JavaScript is one of the most misunderstood concepts. Its value is determined by how a function is called, not where it is defined. The this context can change dynamically. Global Context: In the global execution context (outside of any function), this refers to the global object ( window in browsers, global in Node.js). javascript console.log(this === window); // true (in browser)
  • 30.
    Function Context (SimpleFunction Call): In a regular function call, this also refers to the global object (or undefined in strict mode). javascript function showThis() { console.log(this); } showThis(); // window object (non-strict), undefined (strict) Method Context: When a function is called as a method of an object, this refers to the object that owns the method. javascript const person = { name: "Alice", greet: function() { console.log(`Hello, my name is ${this.name}`); } }; person.greet(); // "Hello, my name is Alice" Constructor Context: When a function is used as a constructor with the new keyword, this refers to the newly created instance of the object. javascript function Car(make) { this.make = make; } const myCar = new Car("Toyota"); console.log(myCar.make); // "Toyota" Explicit Binding ( call , apply , bind ): call() : Invokes the function with a specified this value and arguments provided individually. apply() : Invokes the function with a specified this value and arguments provided as an array. bind() : Returns a new function, allowing you to permanently set the this context. ```javascript const anotherPerson = { name: "Bob" }; function sayName() { console.log(this.name); } sayName.call(anotherPerson); // "Bob" sayName.apply(anotherPerson); // "Bob" const boundSayName = sayName.bind(anotherPerson); boundSayName(); // "Bob" ``` Arrow Functions and this : Arrow functions do not have their own this context. They inherit this from their lexical (enclosing) scope. This makes them
  • 31.
    very useful incallbacks where you want to preserve the this context of the surrounding code. javascript const user = { name: "Charlie", logMessages: function() { setTimeout(() => { console.log(`Hello from ${this.name}`); // 'this' refers to 'user' }, 1000); } }; user.logMessages(); // "Hello from Charlie" (after 1 second) Prototypes and Prototypal Inheritance JavaScript is a prototype-based language, meaning that objects can inherit properties and methods directly from other objects. Every JavaScript object has a prototype, which is another object that it inherits properties and methods from. The prototype chain is how inheritance works in JavaScript. __proto__ and [[Prototype]] : Every object has an internal [[Prototype]] property, which points to its prototype object. This is often exposed via the __proto__ property (though Object.getPrototypeOf() is the standard way to access it). prototype property of functions: Functions in JavaScript also have a prototype property. When a function is used as a constructor (with new ), the prototype property of the constructor function becomes the [[Prototype]] of the newly created object. ```javascript function Vehicle(make) { this.make = make; } Vehicle.prototype.getMake = function() { return this.make; }; const car = new Vehicle("Honda"); console.log(car.getMake()); // "Honda" console.log(car.proto === Vehicle.prototype); // true console.log(Object.getPrototypeOf(car) === Vehicle.prototype); // true ``` Prototype Chain: When you try to access a property or method on an object, JavaScript first looks for it directly on the object. If it doesn't find it, it then looks on the object's prototype, then on the prototype's prototype, and so on, until it reaches null (the end of the chain). javascript // Example of prototype chain console.log(car.toString()); // Inherited from Object.prototype
  • 32.
    console.log(car.__proto__.__proto__ === Object.prototype);// true Hoisting Hoisting is a JavaScript mechanism where variable and function declarations are moved to the top of their containing scope during the compilation phase, before code execution. This means you can use variables and functions before they are declared in your code. Function Hoisting: Function declarations are fully hoisted, meaning both the function name and its definition are moved to the top. So, you can call a function before its declaration. ```javascript hoistedFunction(); // "Hello from hoisted function!" function hoistedFunction() { console.log("Hello from hoisted function!"); } ``` Variable Hoisting ( var ): Variables declared with var are hoisted, but only their declaration is hoisted, not their initialization. This means they are initialized with undefined . javascript console.log(hoistedVar); // undefined var hoistedVar = "I am hoisted"; console.log(hoistedVar); // "I am hoisted" let and const (Temporal Dead Zone): Variables declared with let and const are also hoisted, but they are not initialized. They are in a "Temporal Dead Zone" (TDZ) from the beginning of the block until their declaration is processed. Accessing them before declaration will result in a ReferenceError . javascript // console.log(tdzVar); // ReferenceError: Cannot access 'tdzVar' before initialization let tdzVar = "I am in TDZ"; Event Delegation Event delegation is a technique where you attach a single event listener to a parent element, instead of attaching multiple event listeners to individual child elements. This single listener then listens for events bubbling up from its children. It's particularly useful for dynamically added elements or a large number of similar elements.
  • 33.
    Benefits: * Performance:Reduces the number of event listeners, saving memory and improving performance. * Dynamic Elements: Automatically handles events for elements added to the DOM after the initial page load. * Simpler Code: Less code to write and maintain. <ul id="myList"> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> </ul> const myList = document.getElementById("myList"); myList.addEventListener("click", function(event) { // Check if the clicked element is an LI if (event.target.tagName === "LI") { console.log("Clicked on:", event.target.textContent); event.target.style.color = "red"; } }); // Dynamically add a new item const newItem = document.createElement("li"); newItem.textContent = "Item 4"; myList.appendChild(newItem); // Clicking on Item 4 will also work due to event delegation Error Handling (try...catch...finally) Error handling is crucial for creating robust applications. JavaScript provides the try...catch...finally statement to handle runtime errors gracefully. try block: Contains the code that might throw an error. catch block: Contains the code to be executed if an error occurs in the try block. It receives the error object as an argument. finally block: Contains code that will always be executed, regardless of whether an error occurred or not.
  • 34.
    function divide(a, b){ try { if (b === 0) { throw new Error("Division by zero is not allowed."); } return a / b; } catch (error) { console.error("An error occurred:", error.message); return NaN; // Return Not a Number on error } finally { console.log("Division operation attempted."); } } console.log(divide(10, 2)); // Output: 5, then "Division operation attempted." console.log(divide(10, 0)); // Output: "An error occurred: Division by zero is not allowed.", then NaN, then "Division operation attempted." 9. Modern JavaScript Development Modern JavaScript development involves a rich ecosystem of tools and practices that streamline the development process, improve code quality, and enhance performance. These tools often work together to transform your source code into optimized, production-ready applications. Introduction to npm npm (Node Package Manager) is the default package manager for Node.js and the world's largest software registry. It allows developers to share and reuse code, making it incredibly easy to manage project dependencies and automate development tasks. Installing npm: npm is installed automatically when you install Node.js. package.json : This file is at the heart of any npm project. It stores metadata about the project (name, version, description) and lists all its dependencies ( dependencies for production, devDependencies for development-only tools). json { "name": "my-js-project", "version": "1.0.0", "description": "A simple JavaScript project", "main": "index.js", "scripts": { "start": "node index.js", "test": "echo "Error: no test specified" && exit 1" }, "keywords": [], "author": "Manus AI", "license": "ISC", "dependencies": { "axios": "^1.6.0" }, "devDependencies": { "eslint": "^8.56.0" } }
  • 35.
    Common npm Commands: npminit : Initializes a new package.json file. npm install : Installs all dependencies listed in package.json . npm install <package-name> : Installs a specific package as a production dependency. npm install <package-name> --save-dev or npm install <package- name> -D : Installs a specific package as a development dependency. npm uninstall <package-name> : Uninstalls a package. npm update : Updates packages to their latest compatible versions. npm run <script-name> : Executes a script defined in the scripts section of package.json . Transpilers (Babel) JavaScript is constantly evolving, with new features being added regularly. However, not all browsers or Node.js environments support the latest features immediately. A transpiler (like Babel) converts modern JavaScript code (e.g., ES6+) into an older, backward-compatible version of JavaScript (e.g., ES5) that can run in a wider range of environments. How Babel Works: Babel takes your source code, parses it into an Abstract Syntax Tree (AST), transforms the AST based on configured plugins and presets, and then generates new code from the transformed AST. Presets: Collections of plugins that support a particular set of JavaScript features (e.g., @babel/preset-env for all modern JavaScript features). ``javascript // ES6+ source code const greet = (name) => Hello, ${name}!`; // Transpiled ES5 code (by Babel) var greet = function greet(name) { return "Hello, " + name + "!"; }; ```
  • 36.
    Bundlers (Webpack, Parcel) AsJavaScript applications grow, they often consist of many modules and assets (CSS, images, fonts). Bundlers are tools that combine these separate modules and assets into a single (or a few) optimized bundles for deployment. This reduces the number of HTTP requests a browser needs to make, improving load times. Webpack: A highly configurable and powerful module bundler. It can handle various asset types through loaders and plugins. Parcel: A zero-configuration bundler that aims for a faster and easier development experience. Key functions of bundlers: * Module Resolution: Understands import and require statements to build a dependency graph. * Transpilation: Integrates with transpilers like Babel to convert modern JavaScript. * Minification: Removes unnecessary characters (whitespace, comments) from code to reduce file size. * Code Splitting: Divides code into smaller chunks that can be loaded on demand, improving initial load performance. * Asset Management: Can process and optimize other assets like CSS, images, and fonts. Linting (ESLint) Linting is the process of analyzing source code to flag programming errors, bugs, stylistic errors, and suspicious constructs. Linters help enforce coding standards and identify potential problems early in the development cycle. ESLint: The most popular JavaScript linter. It is highly configurable and allows developers to define their own rules or use popular style guides (e.g., Airbnb, Standard). Benefits of Linting: * Code Quality: Catches common errors and anti-patterns. * Consistency: Ensures a consistent coding style across a team or project. * Early Detection: Identifies issues before they become harder to debug runtime errors. * Improved Readability: Consistent formatting and adherence to best practices make code easier to read and understand. Example ESLint rule:
  • 37.
    // Bad (ESLintwould flag this) var x = 10; // Good const x = 10; These tools collectively form the backbone of a modern JavaScript development workflow, enabling developers to build complex, high-quality, and performant applications efficiently. 10. Best Practices and Tips Writing good JavaScript code goes beyond just knowing the syntax and features. Adhering to best practices, optimizing for performance, and understanding debugging techniques are crucial for building maintainable, scalable, and robust applications. Clean Code Principles Clean code is code that is easy to read, understand, and modify. Following these principles improves collaboration and reduces technical debt. Meaningful Names: Use descriptive names for variables, functions, and classes that clearly indicate their purpose. Avoid single-letter names or abbreviations unless they are universally understood (e.g., i for loop counters). ```javascript // Bad let d = new Date(); let val = calculate(x, y); // Good let currentDate = new Date(); let totalAmount = calculateTotalPrice(itemPrice, quantity); ``` Small Functions: Functions should do one thing and do it well. Keep functions short and focused, ideally no more than 20-30 lines of code. Avoid Global Variables: Minimize the use of global variables to prevent naming collisions and make code more modular. Use modules, closures, or IIFEs to encapsulate variables. Comments: Write comments that explain why the code does something, not what it does (the code itself should be self-explanatory). Remove commented- out code.
  • 38.
    Consistency: Maintain aconsistent coding style (indentation, naming conventions, semicolon usage) across your entire codebase. Linters like ESLint can help enforce this. DRY (Don't Repeat Yourself): Avoid duplicating code. If you find yourself writing the same logic multiple times, extract it into a reusable function or module. Performance Optimization Optimizing JavaScript code ensures that your applications run smoothly and efficiently, providing a better user experience. Minimize DOM Manipulation: DOM operations are expensive. Batch changes, use document fragments, or update innerHTML once instead of multiple times. Avoid Layout Thrashing: Repeatedly reading and writing to the DOM can cause the browser to recalculate layout multiple times. Read all necessary layout properties first, then perform all writes. Optimize Loops: For large arrays, prefer for loops over forEach or map if performance is critical, as native loops can be faster. Cache array.length in for loops. javascript // Good for (let i = 0, len = arr.length; i < len; i++) { // ... } Debouncing and Throttling: For events that fire frequently (e.g., resize , scroll , mousemove , input ), use debouncing or throttling to limit the rate at which event handlers are executed. Lazy Loading: Load resources (images, components, modules) only when they are needed, reducing initial load time. Use const and let : Prefer const and let over var to improve scope management and prevent accidental reassignments, which can sometimes lead to minor performance benefits due to better optimization by JavaScript engines.
  • 39.
    Debugging Techniques Debugging isan essential skill for every developer. Modern browsers provide powerful developer tools to help you find and fix issues. console.log() : The simplest and most common debugging tool. Use console.log() , console.warn() , console.error() , console.table() , console.dir() to inspect values and program flow. Browser Developer Tools: Elements Tab: Inspect and modify HTML and CSS. Console Tab: View logs, errors, and execute JavaScript code. Sources Tab: Set breakpoints, step through code, inspect variables, and modify code on the fly. Network Tab: Monitor network requests and responses. Performance Tab: Analyze runtime performance. Memory Tab: Profile memory usage. Breakpoints: Pause code execution at specific lines to inspect the state of variables and the call stack. debugger keyword: Insert debugger; into your code to programmatically set a breakpoint. When the developer tools are open, execution will pause at this point. Error Messages: Pay close attention to error messages in the console. They often provide valuable clues about the type and location of the problem. Common Pitfalls and How to Avoid Them Loose Equality ( == ) vs. Strict Equality ( === ): Always use === (strict equality) to compare values, as == performs type coercion, which can lead to unexpected results. javascript console.log(0 == false); // true console.log(0 === false); // false console.log("5" == 5); // true console.log("5" === 5); // false
  • 40.
    Floating Point Inaccuracy:JavaScript numbers are 64-bit floating-point. This can lead to precision issues with decimal numbers. Avoid direct comparison of floating-point numbers. javascript console.log(0.1 + 0.2 === 0.3); // false this Context Issues: As discussed, this can be tricky. Be mindful of how functions are called and use arrow functions or bind / call / apply to control this when necessary. Asynchronous Code Complexity: Callback hell, unhandled promises, and race conditions are common. Use Promises and async/await to manage asynchronous flow effectively. Modifying Arrays While Iterating: Avoid adding or removing elements from an array while iterating over it with for...of or forEach , as this can lead to skipped elements or infinite loops. Iterate over a copy or use methods like filter or map to create new arrays. Global Scope Pollution: Declare variables within the narrowest possible scope to avoid unintended side effects and conflicts. By understanding and applying these best practices, you can write more efficient, readable, and maintainable JavaScript code, leading to more robust and successful applications.