Learn JavaScript from Scratch: A Complete Guide

Mayur RogheliyaMayur Rogheliya
19 min read

Understanding JavaScript: Basics and Beyond

JavaScript is a versatile scripting language that brings web pages to life with interactive features and dynamic behavior. It enables complex functionalities on web pages, making it an essential tool for modern web development. Here’s a comprehensive overview of JavaScript, covering its core concepts and advanced features.

Basic Information

What is JavaScript?

JavaScript is a scripting language that allows you to implement complex features on web pages. While HTML provides the structure and CSS the style, JavaScript adds interactivity and special effects.

Characteristics

  • Dynamic Behavior: JavaScript allows dynamic updates to web pages without needing to reload.

  • Validation: Commonly used for form validation on websites.

  • Ease of Use: Can be written in any text editor and executed directly in web browsers.

JavaScript Basics

  • Hoisting: JavaScript moves all declarations to the top of the current scope. This applies to variables and functions.

  • Strict Mode: Enforces a stricter set of rules for writing secure and cleaner code. It helps prevent common coding errors and unsafe actions.

      'use strict'
      // js default behaviour
    
  • Variable Declarations:

    • var: Function-scoped and can be hoisted.

    • let: Block-scoped and can be reassigned.

    • const: Block-scoped and cannot be reassigned.

    • In JavaScript, if you declare a variable without assigning a value to it, the output will be undefined.

Comments in JavaScript

Comments are used to explain code and make it more readable. They are ignored during code execution and do not affect the program's behavior.

  • Single-line comments: Use // to add comments that span a single line.

      // This is a single-line comment
    
  • Multiline comments: Use /* */ to add comments that span multiple lines.

      /*
       * This is a multiline comment
       * It can span multiple lines
       */
    

Displaying Variable Values

To display the values of multiple variables at once, you can use console.table(). This method provides a tabular representation of the data for better readability.

console.table([name, address, phone, email]);

By using console.table(), you can visualize the values of all specified variables in a structured format.

Key JavaScript Concepts

  • JavaScript Engine: JavaScript code is executed by the browser's JavaScript engine, so functions like alert() run within the browser environment.

  • Semicolons: While semicolons (;) are not strictly required in JavaScript, it is a good practice to use them to enhance code readability and avoid potential issues.

  • Handling Undefined Values: If a variable does not display undefined, you can explicitly use null to represent a non-existent or invalid value.

  • Symbols for Uniqueness: Symbols are often used for creating unique identifiers, especially in frameworks like React.js, to avoid naming collisions.

  • Type Checking:

    • console.log(typeof null) outputs: object

    • console.log(typeof undefined) outputs: undefined

  • Comparison and Equality:

    • === checks both the value and its datatype, ensuring strict equality.
  • Language Inconsistencies: JavaScript has some inconsistencies in its design that can lead to unexpected behavior.

  • Code Readability: Focus on writing readable and maintainable code, which is crucial for effective programming.

  • Dynamic Typing: JavaScript is a dynamically-typed language, meaning variable types are determined at runtime.

  • Date Object: In JavaScript, Date is a built-in object used for handling dates and times.

  • Global Object: Within the browser, the global object is the window object, which provides access to global properties and methods.

  • The this Keyword: In JavaScript, this refers to the context in which a function is executed, and it works primarily within objects rather than standalone functions.

Data Types

  • Primitive/in-built Types (immutable):

    1. String

    2. Number

    3. BigInt (15520n)

    4. Boolean

    5. Undefined

    6. Null (standalone value)

    7. Symbol

  • Non-Primitive/derived/reference Types (mutable):

    Every time give a new value

    1. Object

    2. Array

    3. Function

Type Conversion

let score = "18abc";
let score = null;
let score = undefined;
console.log(typeof score); // string

let valueInNumber = Number(score) // convert string to number
console.log(typeof valueInNumber); // number

console.log(valueInNumber); // string-number -> number
console.log(valueInNumber); // string -> NaN
console.log(valueInNumber); // null -> 0
console.log(valueInNumber); // undefined -> NaN
console.log(valueInNumber); // boolean true:1 false:0

Memory Types in JavaScript

JavaScript uses two types of memory to manage data: Stack and Heap.

  • Stack Memory:

    • Used for primitive data types (e.g., number, string, boolean).

    • Variables hold actual values.

    • When you assign a primitive value to a variable, you get a copy of that value.

    let x = 10; // Stack holds the value 10
    let y = x;  // y also holds the value 10
  • Heap Memory:

    • Used for non-primitive data types (e.g., object, array, function).

    • Variables hold references to the memory location where the data is stored.

    • When you assign a non-primitive value to a variable, you get a reference to the original value, not a copy.

    let obj1 = { name: 'Alice' }; // Heap holds a reference to the object
    let obj2 = obj1;              // obj2 references the same object as obj1

Strings in JavaScript

  • String Concatenation

    Instead of using the + operator to concatenate strings, you can use template literals, which are also known as string interpolation. This method provides a cleaner and more readable way to combine strings.

const v1 = 'Hello';
const v2 = 'World';
console.log(`${v1} is ${v2}`); // Output: Hello is World
  • Declaring Strings as Objects

    You can declare a string as an object using the String constructor. This approach creates a string object rather than a primitive string value.

let name = new String("Mayur");
console.log(name[0]); // Output: M
console.log(name.__proto__); // Output: {}

Arrays

  • JavaScript provides several methods for manipulating arrays. Here’s a summary of some common operations:

  • Adding and Removing Elements:

    • push(element): Adds an element to the end of the array.

    • pop(): Removes the last element from the array.

    • unshift(element): Adds an element to the front of the array.

    • shift(): Removes the first element from the array.

  • Handling Out-of-Bounds Indexes:

    • When accessing an index outside the bounds of an array, JavaScript will return -1.
  • Converting Arrays to Strings:

    • arr.join(): Converts an array into a string. For example, [1, 2, 3].join() results in "1,2,3".
  • Difference Between slice and splice:

    • slice(start, end): Returns a new array containing the elements from the start index up to, but not including, the end index. It does not modify the original array.

    • splice(start, deleteCount, item1, item2, ...): Modifies the original array by removing or replacing elements from the start index. It returns an array of the removed elements.

  • Combining and Flattening Arrays:

    • arr1.push(arr2): Adds arr2 as a single element to arr1, resulting in an array of arrays.

    • arr3 = arr1.concat(arr2): Merges arr1 and arr2 into a new array arr3.

    • arr3 = [...arr1, ...arr2]: Uses the spread operator to merge arr1 and arr2 into a new array arr3.

    • arr1.flat(Infinity): Flattens an array of arrays into a single array.

  • Creating Arrays:

    • Array.from("Mayur"): Converts a string into an array of characters.

    • Array.of(num1, num2, num3): Creates a new array with the specified numbers.

Objects

Object Declaration

Objects in JavaScript can be declared in two ways:

  1. Literal Notation:

     const student = {
       name: 'John',
       age: 25
     };
    
  2. Constructor Function:

     function Student(name, age) {
       this.name = name;
       this.age = age;
     }
     const student = new Student('John', 25);
    

Singleton Pattern

When declaring an object using the literal notation, it does not create a singleton object. However, when using the constructor function, it can create a singleton object. Another way to create a singleton object is using Object.create().

Freezing Objects

You can prevent changes to an object by using Object.freeze(). This method makes an object immutable, meaning you cannot change its values or keys after freezing.

Object.freeze(student);

this Keyword

The this keyword refers to the current context or the object to which the method belongs. It provides a reference to the same object.

Accessing Object Values

You can access object values in two ways:

  • Dot notation:

      student.email;
    
  • Bracket notation:

      student['email'];
    

Merging Objects

To merge two objects, you can use either Object.assign() or the spread operator.

  • Using Object.assign():

      const obj3 = Object.assign({}, obj1, obj2);
    
  • Using the spread operator:

      const obj3 = { ...obj1, ...obj2 };
    

Getting Object Keys

To retrieve the keys of an object, use Object.keys():

Object.keys(obj1);

Object Destructuring

In modern JavaScript, you can destructure objects to extract values into variables:

const { name, age } = student;

Functions in JavaScript

In JavaScript, functions are fundamental building blocks. Here’s a breakdown of different types of functions and their characteristics:

Function Calls and Parameters

  • Arguments: Values passed to a function when calling it are called arguments.

  • Parameters: Variables listed as part of a function’s definition that receive the arguments are called parameters.

  • Return Statement: Code after the return statement in a function will not be executed.

Function Types

  1. Declaration Function (Named Functions or Traditional Functions)

     function helloWorld() {
       console.log('Hello World!');
     }
     helloWorld; // This line references the function but does not call it
    
    • Function Call: Can be called before or after the function declaration.

    • Hoisting: Supported.

  2. Expression Function (Anonymous Functions or Lambda Functions)

     let helloWorld = function () { 
       console.log('Hello World!'); 
     }
    
    • Function Call: Can be called only after the function declaration.

    • Anonymous: Can be anonymous.

    • Hoisting: Not supported.

  3. Arrow Function

     let helloWorld = () => { 
       console.log('Hello World!'); 
     }
    
     let helloWorld = () => { 
       return 'Hello World!'; 
     }
    
    • Implicit Return: No need to use return if you use {}.

    • Explicit Return: Use return if you use {}.

    • Fat Arrow: An updated version of function expressions.

    • Function Call: Can be called only after the function declaration.

    • Hoisting: Not supported.

  4. IIFE (Immediately Invoked Function Expressions)

     (function chai() {
       // Named IIFE
       console.log(`DB CONNECTED`);
     })();
    
     // If you use a named function, it's called a named IIFE
    
    • Syntax: ()(); where the first () defines the function and the second () executes it.

    • Global Scope: Helps avoid pollution of the global scope by encapsulating variables.

    • End with ;: Essential to terminate the expression properly.

Advanced Topics

JavaScript Execution Context

JavaScript code execution occurs in two phases:

  1. Memory Creation Phase: Memory is allocated for variables and functions.

  2. Execution Phase: The actual execution of the code happens during this phase.

In the browser environment, the value of this refers to the window object.

JavaScript operates as a single-threaded process.

Types of Execution Contexts

  • Global Execution Context

  • Function Execution Context

  • Eval Execution Context (related to hosting)

Control Flow in JavaScript

Conditional Statements

  • if: Executes a block of code if a specified condition is true.

      if (condition) {
          // Code to execute if condition is true
      }
    
  • if - else: Executes one block of code if a condition is true and another block if it is false.

      if (condition) {
          // Code to execute if condition is true
      } else {
          // Code to execute if condition is false
      }
    
  • if - else if - else: Allows you to test multiple conditions.

      if (condition1) {
          // Code to execute if condition1 is true
      } else if (condition2) {
          // Code to execute if condition2 is true
      } else {
          // Code to execute if none of the above conditions are true
      }
    
  • switch: Evaluates an expression and executes code blocks based on matching cases.

      switch (expression) {
          case value1:
              // Code to execute if expression === value1
              break;
          case value2:
              // Code to execute if expression === value2
              break;
          default:
              // Code to execute if no cases match
      }
    

Falsie Values

In JavaScript, the following values are considered falsie:

  • false

  • 0

  • -0

  • BigInt 0n

  • "" (empty string)

  • null

  • undefined

  • NaN

Truthy Values

The following values are considered truthy:

  • "0"

  • 'false'

  • " " (space)

  • [] (empty array)

  • {} (empty object)

  • function(){} (empty function)

Nullish Coalescing Operator (??)

The nullish coalescing operator returns the right-hand operand when the left-hand operand is null or undefined.

let val1;
val1 = 5 ?? 10;        // val1 is 5
val1 = null ?? 10;     // val1 is 10
val1 = undefined ?? 15; // val1 is 15
val1 = null ?? 10 ?? 20; // val1 is 10

console.log(val1);

Ternary Operator

The ternary operator is a shorthand for the if - else statement.

// condition ? true : false
const iceTeaPrice = 100;
iceTeaPrice <= 80 ? console.log("less than 80") : console.log("more than 80");

Loops

  • Types: for, for-of, for-in, forEach()

  • Array Methods: filter(), map(), reduce()

  • JavaScript provides various methods to iterate over data structures and perform operations. Here's an overview of some key looping mechanisms:

  • for...of loop: Iterates over the values of iterable objects such as arrays, strings, maps, sets, and NodeLists.

      for (const item of iterable) {
        // code to execute
      }
    
  • for...in loop: Iterates over the enumerable properties of an object.

      for (const key in object) {
        // code to execute
      }
    
  • forEach() method: The forEach() method of Array instances executes a provided function once for each array element. It is a higher-order function and does not return any value; it returns undefined.

      array.forEach(element => {
        // code to execute
      });
    
  • filter() method: Creates a new array with all elements that pass the test implemented by the provided function.

      const filteredArray = array.filter(element => condition);
    
  • map() method: Creates a new array with the results of calling a provided function on every element in the calling array. This is used for operations.

      const mappedArray = array.map(element => operation);
    
  • reduce() method: Executes a reducer function (that you provide) on each element of the array, resulting in a single output value.

      const result = array.reduce((accumulator, currentValue) => {
        // code to execute
      }, initialValue);
    
  • Map object: A Map is a collection of unique values and does not allow duplicates. It is not iterable.

      const map = new Map();
    

Callback Function

A callback function is a function that is passed as an argument to another function and is executed after some operation has been completed. It does not have a name and is often used to handle asynchronous operations or to provide custom behavior.

function someFunction(callback) {
  // code
  callback();
}

Document Object Model (DOM)

The DOM (Document Object Model) represents the structure of an HTML document as a hierarchical tree of objects. Here's a brief overview:

  • window: The global object in JavaScript. It represents the window in which the script is running.

    • Hierarchy: window --> document --> html

Properties and Methods

  • innerText: Does not display elements with display: none. It only shows text content visible on the page.

  • innerHTML: Displays elements with display: none. It shows all HTML content inside an element, regardless of its visibility.

Collections

  • NodeList: Not an array, so methods like map are not available. Instead, use forEach to iterate through a NodeList.

  • HTMLCollection: Can be converted into an array using Array.from(variableName) for array methods.

Event Execution

In JavaScript, all events run sequentially. JavaScript is a sequentially executed language, meaning that code runs line by line in the order it is written.

Events in JavaScript

Events are a key part of web development, allowing you to create interactive and dynamic web applications. Here’s a guide on handling events in JavaScript:

  • Adding Event Listeners

    Use addEventListener to handle events because it provides event propagation capabilities and can listen to more types of events.

  • Event Types

    • Browser Events: Events related to user interactions with the browser.

    • Environment Events: Events related to changes in the environment or application state.

  • Event Propagation

    Event propagation has two contexts:

    • Event Bubbling: Events propagate from the target element up to the root (bottom to top). This is the default behavior (false).

    • Event Capturing: Events propagate from the root down to the target element (top to bottom). Set true to use event capturing.

  • Stopping Propagation

    To prevent an event from propagating further, use e.stopPropagation() within the event listener.

  • Preventing Default Behavior

    To prevent the default behavior of a specified event from occurring, use e.preventDefault().

Asynchronous JavaScript

JavaScript is traditionally a synchronous language, executing code line by line. However, it can handle asynchronous operations due to mechanisms such as APIs, setTimeout, setInterval, and more.

  • Synchronous vs Asynchronous:

    • JavaScript executes code synchronously, meaning one operation follows another in a sequential manner.

    • JavaScript also supports asynchronous operations through Web APIs, allowing tasks to be performed in the background, enabling non-blocking behavior.

  • Single Thread Process:

    • JavaScript operates on a single-threaded model, meaning it processes one operation at a time.
  • Blocking Code:

    • Blocking code halts the execution flow until the operation is completed.

    • Example: fs.readFileSync() (synchronous file reading).

  • Non-Blocking Code:

    • Non-blocking code does not stop the execution flow, allowing other operations to continue while waiting for the asynchronous operation to complete.

    • Example: fs.readFile() (asynchronous file reading).

  • Web API / Node:

    • Web APIs are built into the browser and handle asynchronous tasks.

    • setTimeout() and setInterval() are part of this API, used to schedule code execution.

  • Handlers and Callbacks:

    • A handler is a callback function provided to asynchronous methods like setTimeout(). It is referenced by passing the function name, not its execution.

    • In clearTimeout(), the first parameter is the reference to the setTimeout() call.

  • Arguments in setInterval():

    • setInterval() can take additional arguments after the interval time, which are passed to the callback function.

Example:

setTimeout(function() {
  console.log('This is an asynchronous message.');
}, 1000); // 1 second delay

setInterval(function(arg) {
  console.log('Interval message:', arg);
}, 1000, 'Hello'); // 1 second interval with argument

API

  • An API (Application Programming Interface) is a communication system between two languages or systems.

  • For example, to get information about a GitHub user, you can use the following URL:

api.github.com/users/mayurrogheliya
  • Before APIs became common, programmers used XMLHttpRequest, which is related to Ajax (Asynchronous JavaScript and XML).

  • Whenever a response is received from a URL, it is most often in the form of a string. To convert this string into an object, you can use JSON.parse().

  • Additionally, console.log is a debugging tool provided by the JavaScript runtime. It is used to print information to the console for developers to inspect and debug their code.

Promises in JavaScript

A Promise is an object in JavaScript that represents the eventual completion or failure of an asynchronous operation.

  1. Creating and Consuming Promises

    First, create a Promise and then consume it.

     let myPromise = new Promise((resolve, reject) => {
       // Asynchronous operation
     });
    
  2. Handling Promise Resolution

    • resolve: Used to handle successful completion of the Promise. Chained with .then().

        myPromise.then((result) => {
          // Handle success
        });
      
    • reject: Used to handle failures of the Promise. Chained with .catch().

        myPromise.catch((error) => {
          // Handle error
        });
      

Fetch in JavaScript

The fetch() method is a global function used to make network-based requests.

  • Error Handling: An error is only rejected if the request cannot be made. For instance, network issues or connectivity problems might cause a rejection.

    HTTP errors, such as 404 (Not Found), do not cause the promise to be rejected. Instead, they resolve the promise with an ok property set to false.

  • Data Handling:

    • onfulfilled[]: This handles the data when the promise is resolved.

    • onrejection[]: This handles the error when the promise is rejected.

  • Environment:

    • In both web browsers and Node.js, the fetch() method is used for network requests and returns a promise that can be resolved or rejected based on the request's success or failure.

Object-Oriented Programming (OOP) in JavaScript

  • JavaScript does have classes, but technically it does not have traditional classes as seen in some other languages. Therefore, it is not considered a fully object-oriented language.

  • JavaScript is primarily a prototype-based language.

  • Object-Oriented Programming (OOP) is a programming paradigm that focuses on the style and structure of code.

Object Literal

In JavaScript, an object literal is a straightforward way to define objects.

const date = new Date();
  • new is a constructor function that builds or creates multiple instances from the same object.

  • return this indicates that the object itself is being returned, allowing the current context to be passed on.

  • In the example above, new Date() creates a new instance of the Date object.

The new Keyword in JavaScript

The new keyword is used to create a new instance of an object. Here's a breakdown of how it works:

  1. Object Creation: The new keyword first creates a new, empty object, referred to as an instance.

  2. Constructor Function Call: The constructor function is called as a result of using the new keyword. It packs the arguments and provides them to the constructor function.

  3. Argument Injection: The arguments are injected into the this keyword, making them available within the constructor function.

  4. New Instance: Each time the constructor function is called with the new keyword, it returns a new instance of the object.

Prototype in JavaScript

JavaScript's default behavior is prototype-based. This allows for the following:

  • new Keyword: Used to create instances of objects.

  • this Keyword: Refers to the context in which a function is called.

  • Class: A syntactic sugar over JavaScript's prototype-based inheritance.

Prototype Chain

  • Array → Object → null

  • String → Object → null

  • Function → Object → null

In JavaScript, all prototypes are objects, and the object of a prototype is null.

Every entity in JavaScript is an object, and the properties of the object are also available on these entities.

JavaScript provides constructors using the new keyword.

Class Constructor in JavaScript

  • Class Keyword: class is a keyword used to define a class.

  • Constructor: When creating an object using the new keyword, the constructor of the class is called. The constructor initializes the object.

      class MyClass {
        constructor() {
          // Initialization code here
        }
      }
      const myObject = new MyClass(); // Constructor is called here
    
  • instanceof: The instanceof operator checks if an object is an instance of a particular class.

      myObject instanceof MyClass; // Returns true if myObject is an instance of MyClass
    
  • Static Methods: Static methods belong to the class itself, not to instances of the class. They cannot be accessed from an instance of the class or used to create instances.

      class MyClass {
        static myStaticMethod() {
          // Static method code here
        }
      }
      MyClass.myStaticMethod(); // Accessed directly from the class, not from an instance
    

Getters and Setters in JavaScript

  • Getter: Retrieves the value of a property. It is defined using the get keyword.

      get propertyName() {
        // code to get the value
      }
    
  • Setter: Sets the value of a property. It is defined using the set keyword.

      set propertyName(value) {
        // code to set the value
      }
    

Closure and Lexical Scope

  • Lexical Scope: In JavaScript, lexical scope means that functions have access to variables defined in their outer (enclosing) scopes. For example, an inner function can access variables from its outer function, but the outer function cannot access variables from its inner function. This is akin to a child getting ice-cream from the parent, but the parent not getting ice-cream from the child.

  • Closure: A closure occurs when a function retains access to its lexical scope even after the function has finished executing. This means that not only the function is returned, but the entire lexical scope is returned as well.

  • Event Handlers: The onclick event requires a function to be assigned to it.

// Example of a closure
function outerFunction() {
  let outerVariable = 'I am outside!';

  function innerFunction() {
    console.log(outerVariable); // Accesses outerVariable
  }

  return innerFunction; // Returns the inner function
}

const myFunction = outerFunction(); // myFunction is now a closure
myFunction(); // Logs: 'I am outside!'

Conclusion

JavaScript is a powerful language that has evolved significantly, allowing developers to create rich and interactive web applications. From its basics like variables, functions, and loops to advanced concepts like asynchronous programming and the DOM, mastering JavaScript is essential for modern web development. By understanding its core principles and leveraging its capabilities, you can build efficient, maintainable, and scalable web applications.

0
Subscribe to my newsletter

Read articles from Mayur Rogheliya directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Mayur Rogheliya
Mayur Rogheliya

I am passionate about learning, sharing knowledge, and growing through meaningful connections. My journey is all about embracing new challenges, evolving with every step, and collaborating with others to build something impactful.