JavaScript Foundations: From Variables to Functions by Bob Tabor

This document offers an introduction to JavaScript programming, starting with fundamental concepts like saving files, executing code in environments like Node.js, and understanding the difference between the language and its runtime environment. It progresses to explain JavaScript syntax, comparing it to English, and introduces variables, their declaration keywords (let, var, const), and naming conventions. The text then explores data types (number, string, boolean, undefined), type coercion, and essential operators for various operations. Further topics include arrays for managing lists of data, functions (declarations, expressions, immediately invoked function expressions), decision statements (if, switch, ternary), and iteration (for, while loops). It also covers variable scope, the module pattern for managing global scope issues, closures, the behavior of the ‘this’ keyword, destructuring arrays and objects, and template literals for flexible string creation. Finally, it touches upon regular expressions, built-in native objects like String and Array, constructor functions, the conceptual equivalence of classes in JavaScript, and arrow functions, concluding with a brief overview of the Date object and useful string and array methods.

JavaScript Foundations From Variables to Functions by Bob Tabor amjadizhar blog

JavaScript Fundamentals: A Beginner’s Guide

JavaScript is a popular programming language, and this course is designed for absolute beginners, including those new to programming in general. It assumes some familiarity with HTML and CSS and focuses on teaching the pure JavaScript language rather than being a web development course, although JavaScript’s use in web browsers will be discussed towards the end. The course emphasizes writing console or command-line style applications to isolate the language itself from HTML and CSS complexities.

Here are some fundamental aspects of JavaScript:

  • Tools for Development
  • You will need a web browser (Microsoft Edge or Google Chrome are recommended).
  • Node.js is required as the JavaScript runtime environment to execute code. It’s essentially the V8 JavaScript engine from Chrome with added tools for server-side functionalities, though for this course, it’s used for simple console output.
  • An authoring tool like Visual Studio Code (VS Code) is highly recommended. It’s free, cross-platform, and provides features like code coloring, code completion (IntelliSense), file management, and an integrated terminal.
  • Execution Environments JavaScript code can be executed in several environments:
  • Node.js: Typically used for server-side applications that interact with the file system, network, or handle HTTP requests/responses.
  • Web Browser: Used for dynamically interacting with HTML elements on a web page.
  • Other environments: Like Unity for video game development. It’s important to understand the distinction between the JavaScript language itself and the environment it runs in. For instance, console.log exists in both Node.js (to print to the command line) and web browsers (for debugging messages in developer tools).
  • Language Fundamentals
  • Statements and Expressions:
  • A statement is a complete instruction, like a sentence in English, ending with a semicolon. JavaScript files contain one or more statements executed sequentially.
  • A statement consists of one or more expressions.
  • An expression is made up of operators (like keywords, +, =) and operands (like variable names or function calls).
  • Examples of expressions include variable declarations (let a), value assignments (a = 4), and evaluations that return a single value (b + c).
  • Case Sensitivity: JavaScript is case-sensitive. console with a capital ‘C’ is different from console with a lowercase ‘c’.
  • Comments:
  • Single-line comments start with two forward slashes (//).
  • Multi-line comments start with /* and end with */.
  • Variables
  • A variable is an area in the computer’s memory to store and retrieve values.
  • Declaration Keywords:
  • let: The recommended keyword for declaring variables in modern JavaScript, behaving like variables in most other programming languages.
  • var: The original keyword, still widely seen in tutorials and articles, but its usage is nuanced and can lead to unexpected ramifications due to its scope behavior.
  • const: Used for variables whose values are not intended to change after initialization. Attempting to reassign a const variable will result in an error.
  • Naming Rules for Identifiers:
  • Must begin with a letter, dollar sign ($), or an underscore (_).
  • Can contain letters, numbers, dollar signs, or underscores.
  • Cannot contain spaces or other special characters.
  • Cannot be a keyword (e.g., let cannot be a variable name).
  • Are case-sensitive (x is different from X).
  • Naming Conventions (Best Practices):
  • Descriptive names: Should represent the data being stored (e.g., firstNumber instead of x).
  • Camel casing: First word lowercase, subsequent words capitalized (e.g., firstName, zipCode).
  • Consistency: Maintain a consistent naming style throughout the application.
  • Avoid relying on case: Don’t create variables like zipCode and ZipCode as separate entities, as it reduces readability.
  • Assignment Operator (=): Used to assign a value to a variable. A variable can be declared once but assigned values multiple times.
  • Initialization: Assigning a value to a variable at the moment of declaration (e.g., let x = 7). If not initialized, a variable’s value is undefined.
  • Scope (Basic): Variables have a lifespan and citizenship determined by where they are declared.
  • Variables declared in an outer scope are visible in all inner (child) scopes.
  • Variables declared in an inner scope are not available in outer scopes; they “die” and are removed from memory once their code block finishes execution.
  • Data Types
  • In JavaScript, values have data types, not the variables themselves. A variable can hold different types of values over its lifespan.
  • Primitive Data Types:
  • Number: Any positive or negative number, including decimals.
  • Boolean: true or false.
  • String: A sequence of characters, usually represented with single or double quotes (e.g., ‘hello world’).
  • Undefined: The value a variable has when declared but not yet assigned a value.
  • Null: Represents a variable that points to nothing, typically when an object reference was expected. It’s considered an object type when using typeof due to a known bug.
  • Symbol: A new primitive type in the latest JavaScript version, not covered in depth.
  • Complex Data Types:
  • Object: A collection of related properties and methods. Arrays are a type of object.
  • Function: A block of code that can be named and called. Functions are also considered a data type.
  • Type Coercion
  • JavaScript can automatically coerce (convert) data types when incompatible types are used together (e.g., adding a number and a string will convert the number to a string and then concatenate them).
  • Explicit Coercion: You can force conversion using built-in functions like parseInt() to convert a string to an integer, specifying the radix (base system, usually 10).
  • NaN (Not a Number): Returned by parseInt() or other numeric operations if the conversion or calculation results in something that isn’t a valid number. isNaN() can be used to check for this.
  • Operators
  • Assignment: = (assigns value).
  • Arithmetic: + (addition), – (subtraction), * (multiplication), / (division).
  • Increment/Decrement: ++ (increments by 1), — (decrements by 1). Can be prefix (++a, first evaluate then use) or postfix (a++, first use then evaluate).
  • Modulus (%): Returns the remainder of a division.
  • String Operators: Single/double quotes for literal strings, + for string concatenation.
  • Precedence: Parentheses () control the order of operations, similar to algebra.
  • Function Invocation: () after a function name to execute it.
  • Member Accessor: . (dot notation) to access properties or methods of an object (e.g., console.log).
  • Array Element Access: Square brackets [] to access elements in an array by index (e.g., a).
  • Logical Operators: && (AND), || (OR) for combining conditions.
  • Equality Operators:
  • == (equality): Checks if two values are equal, performing type coercion if necessary.
  • === (strict equality): Checks if two values are equal AND of the same data type, without coercion.
  • != (not equal to): Checks for inequality.
  • !== (strict not equal to): Checks for strict inequality.
  • Functions
  • A function is a named block of reusable code.
  • Function Declaration: Defined using the function keyword, an identifier (name), parameters in parentheses, and a body in curly braces (e.g., function sayHello() { … }).
  • Function Expression: A function defined as part of an expression, often assigned to a variable, and can be anonymous (without a name). Useful for callbacks.
  • Arguments/Parameters: Values passed into a function, defined within the parentheses.
  • Return Values: Functions can return a single value using the return keyword.
  • Immediately Invoked Function Expression (IIFE): A function expression that is defined and executed immediately. It’s enclosed in parentheses and followed by another set of parentheses for invocation (e.g., (function() { … })();). Often used to create a private scope.
  • Arrow Functions: A concise, shorthand syntax for writing function expressions, especially useful for simple functions or callbacks. They use => (fat arrow operator).
  • Decision Statements
  • if-else if-else: Executes different blocks of code based on conditions that evaluate to true or false.
  • switch: Evaluates an expression against multiple case values. Uses break statements to exit a case block and prevent “fall-through”.
  • Ternary Operator: A shorthand if-else statement that performs a quick inline evaluation and returns one of two values (e.g., condition ? valueIfTrue : valueIfFalse).
  • Iteration Statements (Loops)
  • Allow code blocks to run multiple times until a condition is met.
  • for loop: Has three parts: initialization, condition, and increment/decrement (e.g., for (let i = 0; i < 10; i++) { … }). Often used to iterate a fixed number of times or through arrays using length.
  • while loop: Continues to execute as long as a specified condition is true. More flexible, as the iteration control can be embedded within the loop’s body.
  • break: Exits a loop or switch statement immediately.
  • Objects
  • An object stores related properties (attributes) of a single data element.
  • Object Literal Syntax: Defined using curly braces {} with name: value pairs for properties and methods.
  • Properties: Named values that define characteristics (e.g., make: ‘BMW’).
  • Methods: Functions defined inside an object (e.g., printDescription: function() { … }).
  • Accessing Properties/Methods: Use dot notation (object.property) or bracket notation (object[‘property’]). Dot notation is generally preferred.
  • Objects can be dynamically modified (properties added/removed).
  • Can contain complex structures like nested objects or arrays of objects.
  • Related to JSON (JavaScript Object Notation), a common format for data exchange, with very similar but not identical syntax to object literals.
  • Arrays
  • A variable that can hold many different values (a list of information).
  • Declared using square brackets [] with comma-separated values (e.g., let a =).
  • Elements are zero-indexed (first element is at index 0).
  • Can hold elements of different data types within the same array.
  • length property: Returns the number of elements in the array (not zero-indexed).
  • Common Array Methods:
  • push(): Adds one or more elements to the end.
  • pop(): Removes the last element.
  • shift(): Removes the first element.
  • unshift(): Adds one or more elements to the beginning.
  • concat(): Combines two or more arrays.
  • join(): Joins all elements into a single string, with an optional separator.
  • reverse(): Reverses the order of elements.
  • sort(): Sorts the elements (lexicographically for strings, numerically for numbers).
  • indexOf(): Returns the first index at which a given element can be found.
  • lastIndexOf(): Returns the last index at which a given element can be found.
  • map(): Creates a new array by calling a function on every element of the original array.
  • filter(): Creates a new array with all elements that pass a test implemented by a provided function.
  • forEach(): Executes a provided function once for each array element.
  • every(): Checks if all elements in an array pass a test.
  • some(): Checks if at least one element in an array passes a test.
  • Error Handling
  • JavaScript’s runtime will throw an exception and quit if it encounters something it cannot work with.
  • try-catch-finally: A construct to safeguard code.
  • try: Contains code that might throw an exception.
  • catch: Executes if an exception is thrown in the try block, allowing you to handle the error (e.g., inspect the Error object’s message property).
  • finally: Executes regardless of whether an exception occurred or was caught, typically for cleanup.
  • Throwing Custom Errors: You can use throw new Error(“message”) to communicate failures from a function to its caller.
  • Advanced Topics (Introduced as Basics)
  • this Keyword: Represents the context in which a function is called, and its value depends on how the function is invoked (e.g., globally, as an object method, using call() or apply()). In a web browser, this can refer to the window object (global context) or the DOM element that triggered an event.
  • Destructuring: A syntax for “unpacking” values from arrays or properties from objects into distinct variables or other array/object elements.
  • Template Literals: Use backticks (`) to create strings that can span multiple lines and embed expressions using ${expression} (interpolation).
  • Regular Expressions (Regex): Patterns used to search, match, and manipulate strings. While complex, basic use involves creating patterns (/pattern/) and using string methods like test() (checks for match), replace() (replaces matches), and match() (returns match details).
  • Built-in Natives (Primitive Wrappers): Primitive types like string, number, and boolean have corresponding built-in “native” functions (e.g., String, Number, Boolean) that return objects with rich sets of methods. JavaScript automatically “boxes” (wraps) primitives into these objects when methods are called and “unboxes” them back to primitives.
  • Constructor Functions: Normal functions that, when called with the new keyword, create and initialize a new object instance. The new keyword binds the newly created empty object to this inside the constructor function. Constructor functions are conventionally named with an uppercase first letter.
  • Prototype Chain (Prototypal Inheritance): JavaScript’s mechanism for inheritance. Objects can link to other objects (prototypes), forming a chain. When a property or method is accessed on an object, JavaScript searches up this chain until it finds the definition.
  • Classes: Introduced in modern JavaScript as syntactic sugar over the existing object and prototype models. They provide a more familiar class-like syntax (class Car { constructor() {} method() {} }) but internally still rely on prototypes. They can extend other classes to approximate inheritance.
  • Closures: Allow a function to “remember” and access variables from its outer (lexical) environment even after the outer function has finished executing. Each closure creates its own “lexical environment”.
  • Truthy and Falsy Values: JavaScript evaluates certain values as true (truthy) or false (falsy) in a boolean context, even if they are not explicitly boolean. Examples of falsy values include false, null, undefined, 0, NaN, and empty strings (”, “”). Everything else is generally truthy.
  • JavaScript in Web Browsers (DOM)
  • The Document Object Model (DOM) is an object-based representation of an HTML page, allowing programmatic access and manipulation of elements, their attributes, and text.
  • Web browsers construct the DOM by parsing HTML, applying CSS styles, and processing JavaScript.
  • JavaScript can interact with the DOM to:
  • Access nodes: Using methods like document.getElementById().
  • Change attributes: Modify properties of DOM elements (e.g., element.style.fontSize).
  • Add/Remove nodes dynamically: Create new elements (document.createElement()) and append them (element.appendChild()) or remove them.
  • Associate event handlers: Attach functions to respond to user interactions (e.g., element.addEventListener(‘click’, function)).
  • It’s generally recommended to keep JavaScript in separate .js files and link them in the HTML using <script src=”file.js”></script> at the bottom of the <body> to ensure DOM elements are loaded before scripts try to access them. Inline JavaScript in HTML attributes (like onclick) or <script> tags in the <head> is generally frowned upon for professional development.

JavaScript Variables and Scope Fundamentals

In JavaScript, understanding variables and their scope is fundamental to writing effective and maintainable code.

Variables

A variable is essentially a named area in the computer’s memory where you can store and retrieve values throughout the lifespan of your application.

JavaScript offers several keywords for declaring variables:

  • let: This is the recommended keyword for declaring variables in modern JavaScript. It allows you to express your intent to create a new variable.
  • var: This was the original keyword for variable declaration. Its usage can be nuanced and may lead to unexpected behaviors, particularly concerning scope, which can be challenging for beginners. It’s generally advised to abandon var unless specifically required.
  • const: This keyword is used when you intend for a variable’s value never to change after its initial assignment. Attempting to reassign a const variable will result in an error.

Variable Assignment and Initialization: The equal sign (=) is the assignment operator, used to assign a value to a variable. When you declare a variable but do not immediately assign it a value, its value is undefined. This is known as declaration without definition. It’s generally preferable to initialize your variables at the moment of declaration if possible.

Naming Rules for Variables (Identifiers): There are strict rules for naming variables (also called identifiers) that, if violated, will cause your application to break:

  • All identifiers must begin with a letter, a dollar sign ($), or an underscore (_).
  • Variable names can contain letters, numbers, dollar signs, or underscores, but no other special characters or spaces.
  • You cannot use JavaScript keywords as variable names (e.g., let cannot be a variable name).
  • Variable names are case-sensitive (e.g., x and X are treated as two different variables).

Code Conventions for Variables (Best Practices): These are not enforced by the JavaScript compiler but are highly recommended for readability and collaboration:

  • Descriptive names: Use names that clearly indicate the purpose or meaning of the data being stored (e.g., firstNumber instead of x).
  • Camel casing: For multi-word variable names, the first word should be lowercase, and subsequent words should start with a capital letter (e.g., firstName, zipCode).
  • Consistency: Maintain a consistent naming style throughout your application.
  • Do not rely on case: Avoid using variable names that differ only by case if they refer to conceptually the same thing, as this can introduce subtle confusion and programming errors (e.g., zipCode and zipcode as distinct variables should be avoided).

Data Types and Variables: It’s important to note that variables themselves do not have a data type; only the values stored inside the variables have a data type. Common data types include number, boolean, string, undefined, object, and function.

Scope

Scope refers to the lifespan and availability of variables and functions within your application. Variables are like people; they have a lifespan (born, do work, die) and a “citizenship” determining where they can be accessed. When a code block finishes executing, variables defined within that block are typically removed from the computer’s memory, meaning they go “out of scope”.

Fundamental Rules of Scope:

  • A variable declared in an outer (parent) code block (scope) is visible and accessible within all inner (child) code blocks that it encloses.
  • Conversely, a variable declared in an inner (child) code block is not available to outer (parent) scopes once that inner block has finished executing.
  • Variables declared in an outer scope can have their values changed by code within inner scopes.

Global Scope: The global scope is the topmost level of scope in JavaScript. While less of an issue in Node.js applications, defining variables and functions in the global scope is a crucial concern and generally considered a bad idea in web development:

  • Memory Consumption: Each variable defined in the global scope remains in the computer’s memory until the web browser tab navigates to a new page, potentially consuming significant memory over time.
  • Naming Collisions: When multiple JavaScript files (your code, libraries, third-party scripts) are loaded on a single web page, defining variables and functions in the global scope increases the likelihood of “naming collisions.” This occurs when two different scripts define variables or functions with the same name, leading to one overwriting the other, causing unanticipated and difficult-to-track bugs.
  • The var keyword, unlike let or const, specifically attaches variables to the global scope (e.g., the window object in a web browser’s Document Object Model, or DOM). Therefore, let is recommended to avoid polluting the global scope.

Solutions to Global Scope Issues (Module Pattern): To mitigate global scope problems, especially in web development, the Module Pattern is a widely used design pattern. This technique employs an Immediately Invoked Function Expression (IIFE) that returns an object.

  • It allows you to define private variables and functions that are not directly accessible from outside the module, promoting encapsulation (hiding implementation details).
  • The IIFE then returns an object containing “public” properties and methods, which are the only parts exposed to the outside world.
  • This significantly reduces the impact on the global scope by consolidating many internal variables and functions under a single, unique module variable.
  • The Revealing Module Pattern is a variation that explicitly lists the public properties and methods within the returned object, offering a cleaner presentation of what is exposed.

Closures (A Related Concept): Closures are a powerful JavaScript concept related to scope. A closure allows a function to remember and access variables from its surrounding lexical environment (the scope in which it was declared), even after that outer function has finished executing.

  • Essentially, it associates some data with a function at the time the function is created.
  • Each closure creates its own lexical environment, meaning it gets its own set of variables and input parameters from its enclosing scope. This allows for functions that are “pre-filled” with certain data based on when and where they were defined and returned.

The this Keyword (Contextual Binding): The meaning of the this keyword in JavaScript is not fixed; it represents the way a given function is called, and its value changes based on the context of that call.

  • Global Context: When a function is called directly in the global scope (not as a method of an object or with explicit binding), this refers to the global object (e.g., global in Node.js, or window in a web browser).
  • Strict Mode: If “use strict” is enabled, calling a function in the global context will cause this to be undefined instead of the global object.
  • Object Methods: When a function is invoked as a method of an object (e.g., myObject.myMethod()), this inside that method refers to the object itself (myObject in this example). This allows methods to access the object’s properties (e.g., this.propertyName).
  • Explicit Binding (call() and apply() methods): Functions in JavaScript have built-in methods, call() and apply(), that allow you to explicitly set the value of this for that function call. The difference between call() and apply() lies in how additional arguments are passed: call() takes them individually, while apply() takes them as an array.
  • DOM Event Handlers: In web browsers, when a function is called from an inline event handler (e.g., onclick=”myFunction(this)”), the this passed as an argument within the HTML refers to the DOM element itself. However, if the handler function itself is defined without explicit binding, the this inside that function will default to the global window object.

Understanding variables and how their scope impacts their availability and behavior is crucial for developing robust JavaScript applications.

JavaScript: Functions, Objects, and Their Interrelation

In JavaScript, functions and objects are core building blocks for structuring and organizing code. They work together to create dynamic and interactive applications.

Functions

A function is a named block of code that can be repeatedly executed throughout your application. Functions serve as a primary construct in JavaScript for accomplishing tasks.

Function Declaration vs. Function Expression:

  • A function declaration uses the function keyword followed by a name (identifier). For example, function sayHello() { … }. Function declarations are “hoisted” to the top of their execution environment, meaning they can be called before they are defined in the code.
  • A function expression is typically an anonymous function (without a name) assigned to a variable. For example, let myFunc = function() { … }. These are often used when a function is needed as an argument to another function or when it’s only called once.

Arrow Functions:

  • Introduced in recent JavaScript versions, arrow functions (=>) provide a shorthand syntax for defining functions. They remove the need for the function keyword and use a “fat arrow” to point to the function body.
  • They can accept input parameters within parentheses and have a body defined by curly braces.
  • Arrow functions are especially useful for concise, inline functions, such as when iterating over arrays with methods like map(), filter(), or forEach().

Key Aspects of Functions:

  • Arguments (Input Parameters): Functions can accept data (arguments) passed into them, which can then be used within the function’s body.
  • Return Values: Functions can return a single value back to wherever they were called using the return keyword. This value can be any data type, including another function.
  • Functions as Data Types: In JavaScript, functions are considered a data type themselves. This means they can be assigned to variables, passed as arguments to other functions, and even returned as values from other functions.
  • Immediately Invoked Function Expressions (IIFEs): An IIFE is a function expression that is executed immediately after it’s defined. It’s typically wrapped in parentheses and then followed by another set of parentheses to invoke it. IIFEs are a common pattern in JavaScript development, particularly for controlling scope and avoiding global variable pollution.

Objects

An object is a container that holds related properties and methods (functions) of a single data element. Unlike arrays, which hold lists of multiple data elements, an object defines the characteristics and behaviors of one specific item.

Creating Objects:

  • Object Literal Syntax: This is the most common way to create an object, using curly braces {} to define a collection of name-value pairs (properties) and functions (methods). For example, let car = { make: “BMW”, model: “745li”, year: 2010 };.
  • Constructor Functions: A constructor function is a regular JavaScript function that is intended to be called with the new keyword. The new keyword creates an empty object, sets it as the this context for the function call, and then the function populates this new object with properties and methods. A convention is to name constructor functions with an uppercase first letter to indicate their intended use with new.
  • Classes (ES6): Introduced as “syntactic sugar” in the latest JavaScript versions, class provides a more familiar structure for defining objects, resembling traditional object-oriented programming (OOP) languages like Java or C#.
  • A class can have a special constructor method that is automatically called when a new instance of the class is created using new.
  • Methods can be defined directly within the class body.
  • The extends keyword allows a class to “inherit” from another class, providing properties and methods from the parent class to the child class. Despite the class and extends keywords, JavaScript still operates on its underlying prototype model for “inheritance”.

Key Aspects of Objects:

  • Properties and Methods: Properties are named values that describe the object (e.g., car.make), while methods are functions associated with the object that define its behavior (e.g., car.printDescription()).
  • Accessing Members: Properties and methods are typically accessed using dot notation (.) (e.g., car.make, car.printDescription()). Bracket notation (car[‘make’]) can also be used, though dot notation is generally preferred.
  • Dynamic Nature: Objects in JavaScript are dynamic; properties and methods can be added or even deleted from an object after it has been created.
  • Object Graphs: Objects can contain other objects or arrays of objects, forming complex data structures known as “object graphs”.
  • JSON (JavaScript Object Notation): JSON shares a very similar syntax with JavaScript object literals, making it a popular format for data interchange between systems.

Interrelation and Key Concepts

Functions and objects are deeply intertwined in JavaScript:

  • The this Keyword: This is a crucial concept, as this represents the context in which a function is called, and its value changes dynamically.
  • When called in the global context, this refers to the global object (e.g., window in browsers, global in Node.js).
  • When a function is invoked as a method of an object (e.g., myObject.myMethod()), this inside that method refers to the object itself (myObject). This allows methods to access the object’s properties (e.g., this.propertyName).
  • The call() and apply() methods allow you to explicitly set the value of this for a function call.
  • In DOM event handlers, this typically refers to the DOM element on which the event listener is defined.
  • Scope and Module Pattern: Functions are fundamental to controlling variable scope. The Module Pattern, which often utilizes an IIFE that returns an object, is a widely used design pattern to encapsulate private variables and functions and expose only “public” ones through a single object, thereby reducing global scope pollution and naming collisions.
  • Closures: Closures are a powerful feature where a function “remembers” and can access variables from its surrounding (lexical) environment even after the outer function has finished executing. This allows a function to be pre-filled with specific data from its creation context.
  • Built-in Natives: JavaScript’s primitive data types (like string, number, boolean) have corresponding “built-in native” constructor functions (e.g., String(), Number()) that return objects. The JavaScript compiler automatically “boxes” primitives into these native objects to provide them with a rich set of methods (e.g., string.toLowerCase()), and “unboxes” them back as needed. Arrays and regular expressions are also built-in natives that are objects and come with their own sets of methods.

JavaScript Control Flow: Logic, Loops, and Error Handling

In JavaScript, control flow refers to the order in which individual statements, instructions, or function calls are executed. By default, JavaScript statements execute sequentially from top to bottom within a file. However, various constructs allow developers to alter this default sequential execution, introducing logic, repetition, and error handling into their applications.

Basic Building Blocks of Code

  • Statements: A statement is one complete instruction to the JavaScript compiler, similar to a sentence in English. Each JavaScript file typically contains one or more statements that usually execute in sequential order.
  • Expressions: Statements are composed of one or more expressions, which are in turn made up of operators and operands. Operators are keywords or symbols (like +, =, let), while operands are values or identifiers (like variable names or function calls). Combining operators and operands creates expressions that perform actions or evaluations.

Categories of Control Flow

JavaScript provides several categories of control flow mechanisms:

  1. Sequential Execution By default, JavaScript code runs from the first line to the last line. This is the simplest form of control flow.
  2. Decision Statements Decision statements allow you to perform different blocks of code based on whether a certain condition evaluates to true or false. JavaScript treats certain values as “truthy” (evaluating to true) or “falsy” (evaluating to false) even if they are not explicitly true or false booleans. For example, null, undefined, 0, NaN, and empty strings (“”, ”) are considered falsy, while an empty object ({}), an empty array ([]), non-empty strings, and any non-zero number are truthy.
  • if / else if / else: This is the most common decision statement.
  • An if statement evaluates an expression; if it’s true, the code block associated with it is executed.
  • You can include optional else if statements to evaluate other expressions if the preceding if or else if conditions were false.
  • An else statement acts as a catch-all, executing its code block if none of the preceding if or else if conditions were true.
  • switch Statement: The switch statement evaluates a single expression against a number of case values.
  • If a case matches the expression’s value, the code block under that case is executed.
  • Without a break statement, execution will “flow through” to subsequent case blocks, including the default case if present. The break statement is used to exit the switch block after a match is found.
  • A default case can be provided to handle situations where none of the case values match.
  • Ternary Operator (? 🙂: This provides a concise, inline way to perform a quick evaluation and return one of two values.
  • It consists of an expression, followed by a question mark (?), then the value to return if the expression is true, a colon (:), and finally the value to return if the expression is false.
  • For example, doesAEqualB ? “equal” : “not equal”.
  • Equality Operators: The source discusses both loose equality (==) and strict equality (===). Loose equality performs type coercion before comparison (e.g., 7 == “7” is true), while strict equality checks both value and data type without coercion (e.g., 7 === “7” is false). Similar operators exist for inequality (!= and !==).
  1. Iteration Statements (Loops) Iteration statements allow a block of code to be executed repeatedly until a specified condition is met.
  • for Loop: A for loop is typically used when you know the number of iterations or want to iterate over a sequence using an index. It has three parts:
  • Initialization: Declares and initializes a counter variable (e.g., let i = 0).
  • Condition: An expression that is evaluated before each iteration; the loop continues as long as this condition is true (e.g., i < 10).
  • Increment/Decrement: An operation performed after each iteration to update the counter (e.g., i++).
  • for loops are often used to iterate through arrays, accessing elements by their index.
  • while Loop: A while loop continues to execute its code block as long as a given condition remains true.
  • It is more flexible than a for loop because the iteration logic (like incrementing a counter or reading to the end of a file) is controlled within the loop’s body, not just in its header.
  • The break statement can be used within both for and while loops to immediately exit the loop, regardless of the loop’s condition.
  1. Error Handling JavaScript applications can encounter “exceptions” or “errors,” which are situations that prevent the code from continuing execution. When an exception occurs, the JavaScript runtime will “quit” at that point, stopping any further code execution.
  • try-catch-finally: This construct allows you to safeguard code that might throw an exception.
  • The try block contains the code that is susceptible to throwing an exception.
  • If an exception occurs within the try block, execution immediately jumps to the catch block, which receives an “error object” containing information about the exception (e.g., error.message). This prevents the application from completely shutting down.
  • The finally block will execute regardless of whether an exception occurred or was caught. It’s often used for cleanup operations.
  • Throwing Custom Exceptions: Developers can explicitly throw a new Error object from their functions to communicate failure to the caller. This allows the calling code to implement contingency or retry logic.

JavaScript Data Types and Coercion

In JavaScript, data types are essentially a description of the kind of data you want to store and what you intend to do with it. Unlike some other programming languages, variables themselves do not have a data type; only the values stored inside the variables have data types.

JavaScript categorizes its data types into several fundamental types:

Primitive Data Types

The core primitive data types discussed include:

  • Number: Used for any positive or negative numbers, including decimal values. If you want to perform math or algebraic operations, you should use a number.
  • Boolean: Represents true or false values. These are the only two possible values for a boolean.
  • String: Represents a sequence of characters. Strings are typically enclosed in single quotes (”) or double quotes (“”). They are often used to display content on the screen.
  • Undefined: This type indicates that a variable has been declared but no value has been assigned or initialized to it. When a variable is undefined, its value is undefined, and its type is also undefined. It’s different from null because undefined implies an expected value was never set, whereas null means an object reference was expected but is currently pointing to nothing.
  • Null: Represents a variable that points to nothing, specifically when an object reference was expected. While its value is null, a known quirk in JavaScript is that typeof null returns “object”, not “null”. This is a known bug that is unlikely to be fixed due to existing code dependencies. It is not zero, undefined, or an empty string.

Other Data Types

  • Object: This is a more complex data type. An object contains the related properties (attributes) and methods of a single data element, contrasting with an array which holds a list of many data items. Arrays themselves are considered a type of object (typeof an array returns “object”). Objects can hold properties of various data types, including other objects or arrays.
  • Function: Functions are considered their own data type in JavaScript. A reference to a function, when its invocation operator () is not used, will reveal its type as function.

The typeof Operator

The typeof operator can be used to determine the data type of a value. For example, typeof x will output the data type of the value currently stored in x.

Type Coercion

JavaScript can sometimes automatically convert one data type into another in certain operations, a process known as coercion. This can lead to unexpected results.

  • For instance, the plus operator (+) performs double duty: it can be the addition operator for numbers or the string concatenation operator for strings.
  • If you attempt to “add” a number and a string (e.g., 7 + “6”), JavaScript will coerce the numeric value into a string and then concatenate the two strings (resulting in “76”).
  • To force a string to be treated as a number for arithmetic operations, you can use built-in functions like parseInt(). parseInt() takes a string and an optional radix (base system, e.g., 10 for decimal) to convert the string into an integer.
  • If a string cannot be converted into a numeric value, parseInt() (or other numeric conversion attempts) might return NaN (Not a Number), which is a special numeric value indicating an invalid or unrepresentable number.

Primitive Types and Built-in Natives

JavaScript provides “built-in native” functions (or constructors) for primitive types like String, Number, and Boolean, distinguished by their uppercase first letter.

  • These native functions return objects that provide a rich set of methods and properties (e.g., value.replace() for strings, string.toLowerCase(), string.length).
  • When you use a primitive value (like a literal string “howdy”) and call a method on it (e.g., “howdy”.toLowerCase()), the JavaScript compiler coerces or “boxes” that primitive into its corresponding built-in native object behind the scenes to provide the method, and then “unboxes” it back into a primitive when needed, without explicit developer intervention.
  • You can explicitly create instances of these native objects using the new keyword (e.g., new String(“howdy”)), and then use the .valueOf() method to convert them back into their primitive equivalents. However, it is generally recommended to stick with using the primitive types and let JavaScript handle the boxing and unboxing automatically.

Truthiness and Falsiness

In decision statements (like if or switch), JavaScript evaluates expressions to determine if they are “truthy” or “falsy”.

  • Falsy values are those that, when evaluated in a boolean context, are treated as false:
  • false
  • null
  • undefined
  • 0 (the number zero)
  • NaN (Not a Number)
  • “” or ” (empty strings)
  • Truthy values are all other values that are not explicitly falsy, meaning they evaluate to true in a boolean context:
  • true
  • Empty objects ({})
  • Empty arrays ([])
  • Non-empty strings
  • Any non-zero number (integers or floats)
  • Infinity (positive or negative)
Javascript tutorial for beginners Full course | javascript Full crash course for Beginners

By Amjad Izhar
Contact: amjad.izhar@gmail.com
https://amjadizhar.blog


Discover more from Amjad Izhar Blog

Subscribe to get the latest posts sent to your email.

Comments

Leave a comment