JavaScript FoundationsIntroductionJavaScript is the programming language that adds behavior and interaction to web pages. HTML describes structure, CSS controls presentation, and JavaScript responds to events, processes data, changes the document, and communicates with web services. Although JavaScript is commonly used in browsers, it is also used on servers, in desktop applications, mobile applications, and development tools. A strong foundation in JavaScript requires more than memorizing syntax. A programmer must understand how values are represented, how expressions are evaluated, how decisions and repetition are implemented, and how errors are interpreted. This chapter introduces the core language features required for safe and readable beginner programs. Learning ObjectivesBy the end of this chapter, you should be able to: - include and execute JavaScript in an HTML document;
- explain strict mode and its benefits;
- declare variables using
let, const, and, with caution, var; - distinguish primitive values from reference values;
- use arithmetic, comparison, logical, assignment, and conditional operators;
- explain type conversion and truthy and falsy values;
- construct expressions, conditional statements, and loops;
- identify common runtime errors and use browser tools to investigate them;
- apply basic conventions for readable, maintainable code.
1. Executing JavaScriptJavaScript can be written directly in an HTML document using a script element: <script>
console.log("Page loaded");
</script>For maintainability, scripts are normally stored in a separate file: <script src="app.js" defer></script> The src attribute identifies the file. The defer attribute tells the browser to download the script while parsing HTML but execute it after the document has been parsed. Deferred scripts preserve the order of deferred script execution and are usually appropriate when a script needs to access page elements. A script may also be placed at the end of the body, where earlier elements have already been parsed. The defer approach makes the intended loading behavior clearer and avoids scattering scripts through the document. JavaScript statements are commonly separated by line breaks or semicolons. JavaScript has automatic semicolon insertion, but relying on it in complex code can make errors harder to understand. A consistent style—either using semicolons or following a well-defined no-semicolon standard—is preferable. The browser provides a developer console for output and diagnostics: console.log("Debugging message");
console.warn("Possible problem");
console.error("Something failed");These methods are development tools, not substitutes for user-facing messages. 2. Strict ModeStrict mode changes JavaScript’s behavior so that several unsafe or confusing practices produce errors. It is enabled with a directive: "use strict"; Strict mode prevents accidental creation of global variables. For example: "use strict";
score = 10; // ReferenceError: score has not been declared Without strict mode, older JavaScript behavior could create a property on the global object, making the program difficult to maintain. Strict mode also rejects certain duplicate parameter declarations and restricts some legacy features. JavaScript modules are automatically interpreted in strict mode, so files using type="module" do not need to include the directive: <script type="module" src="app.js"></script> Strict mode does not make a program secure by itself. It improves error detection and encourages disciplined programming, but input validation, access control, and safe handling of untrusted data remain necessary. 3. Variables and ConstantsA variable is a named reference to a value. Modern JavaScript provides let and const; var exists mainly for compatibility with older code. let quantity = 3;
const taxRate = 0.2; let permits reassignment:
let status = "pending";
status = "approved"; const prevents reassignment of the variable binding:
const country = "Kenya";
// country = "Ghana"; // TypeError A const object can still have its properties changed because the binding, not the object’s contents, is constant: const user = { name: "Asha" };
user.name = "Mina"; // permittedUse const by default and use let when reassignment is required. The older var is function-scoped rather than block-scoped and can produce surprising behavior. It should generally be avoided in new code. Scope and the Temporal Dead ZoneScope defines where a name can be used. Variables declared with let and const are block-scoped: if (true) {
let message = "inside";
console.log(message);
}
// console.log(message); // ReferenceErrorThe variable exists only within the braces. A let or const declaration cannot be used before its declaration; this period is called the temporal dead zone. Clear declaration before use improves readability and prevents errors. Naming ConventionsNames should communicate purpose. Common conventions include: - use
camelCase for variables and functions, such as totalPrice; - use descriptive names rather than abbreviations, such as
customerCount; - use uppercase names sparingly for genuine constants, such as
MAX_RETRIES; - avoid names that shadow important built-in objects, such as
Object or Array; - do not use reserved words such as
class, return, or for as identifiers.
4. Values and Data TypesJavaScript is dynamically typed. A variable does not permanently have one type; the value assigned to it has a type. let value = 42; // number
value = "forty-two"; // string The primitive data types are string, number, bigint, boolean, undefined, symbol, and null. | Type | Example | Purpose |
|---|
| string | "hello" | Text | | number | 12, 3.5 | Integers and floating-point values | | bigint | 123n | Very large integers | | boolean | true | Logical state | | undefined | undefined | Missing assigned value | | symbol | Symbol("id") | Unique identifiers | | null | null | Intentional absence of an object value |
The typeof operator reports a type: typeof "hello"; // "string"
typeof 7; // "number"
typeof false; // "boolean"
typeof undefined; // "undefined" There is a historical language irregularity: typeof null returns "object". Therefore, typeof alone should not be used to distinguish null from objects. Primitive and Reference ValuesPrimitive values are immutable values. Operations produce new values rather than modifying the original primitive. Objects, including arrays and functions, are reference values. Variables holding objects contain references to objects in memory. let first = 10;
let second = first;
second = 20;
// first is still 10
const original = { points: 5 };
const copy = original;
copy.points = 8;
// original.points is now 8The second object variable does not contain an independent copy; both variables refer to the same object. This distinction is important when passing objects to functions or updating arrays. Arrays are ordered collections: const colors = ["red", "green", "blue"];
console.log(colors[0]); // red Objects store properties using keys: const product = {
name: "Notebook",
price: 4.5
};
console.log(product.name);5. Operators and ExpressionsAn expression produces a value. A statement performs an action and may contain expressions. In total = price * quantity, the multiplication is an expression and the assignment is part of a statement. Arithmetic OperatorsThe arithmetic operators include +, -, , /, %, and *. const subtotal = 12 * 3;
const remainder = 10 % 3; // 1
const squared = 4 ** 2; // 16 The + operator adds numbers but concatenates strings when string conversion occurs: 2 + 3; // 5
"2" + 3; // "23" Parentheses should be used when they make intended precedence clear. Multiplication and division are evaluated before addition and subtraction, but explicit parentheses reduce ambiguity. Assignment OperatorsAssignment stores a value: let count = 1;
count += 2; // equivalent to count = count + 2
count *= 3; The increment and decrement operators, ++ and --, add or subtract one. In beginner code, separate statements are often clearer than embedding them in larger expressions. Comparison OperatorsStrict equality and inequality are written === and !==: 5 === 5; // true
5 === "5"; // false They compare both value and type. The loose operators == and != perform implicit conversion and can produce surprising results. Use strict comparison unless a deliberate reason exists to use loose comparison. Relational operators include <, >, <=, and >=. When both operands are strings, comparison is lexicographic rather than numerical, so explicit conversion may be necessary. Logical OperatorsThe logical operators are && (AND), || (OR), and ! (NOT): const eligible = age >= 18 && hasId;
const displayName = nickname || "Guest";
const unavailable = !available; These operators use short-circuit evaluation. In a && b, b is evaluated only if a is truthy. In a || b, b is evaluated only if a is falsy. The operators return one of their operands, not necessarily a boolean. The nullish coalescing operator ?? supplies a fallback only when the left operand is null or undefined: const quantity = enteredQuantity ?? 1; This differs from ||, which also replaces valid falsy values such as 0 and an empty string. Conditional OperatorThe conditional, or ternary, operator selects one of two expressions: const label = score >= 50 ? "Pass" : "Fail"; It is suitable for short choices. Nested ternary expressions are usually less readable than ordinary if...else statements. 6. Type Conversion and TruthinessType conversion may be explicit or implicit. Explicit conversion is easier to understand and control: const text = "42";
const number = Number(text); // 42
const output = String(number); // "42"
const flag = Boolean(number); // true Number("hello") produces NaN, meaning “Not a Number.” Number.isNaN(value) tests specifically for the NaN value.
parseInt and parseFloat parse numeric text, but they should be used with care. parseInt("12px", 10) returns 12, while Number("12px") returns NaN. The radix argument should be supplied to parseInt when interpreting integer text.
A value is truthy or falsy when used in a boolean context. Falsy values include false, 0, -0, 0n, "", null, undefined, and NaN. Most other values, including empty arrays and empty objects, are truthy. if (items.length > 0) {
console.log("Items available");
}For form data, conversion and validation should be separate steps. An empty input should not automatically be treated as a valid zero. 7. Conditional StatementsAn if statement runs code when a condition is truthy: if (temperature > 30) {
message = "Hot";
} else if (temperature >= 20) {
message = "Moderate";
} else {
message = "Cool";
}Conditions should express business rules clearly. If many fixed alternatives are based on one value, switch may be appropriate: switch (role) {
case "admin":
access = "full";
break;
case "editor":
access = "limited";
break;
default:
access = "none";
}The break prevents fall-through into the next case. A missing break is sometimes intentional, but it should be clearly documented. 8. Loops and RepetitionA for loop is suitable when initialization, continuation, and update are known: for (let i = 0; i < 5; i++) {
console.log(i);
}A while loop continues while its condition is true: while (attempts < 3) {
attempts++;
}The loop must make progress toward termination. Failure to update the controlling condition can create an infinite loop and freeze a page. For arrays, for...of iterates over values: for (const color of colors) {
console.log(color);
}for...in iterates over enumerable property names and is generally more suitable for object properties than array values.
break exits a loop, while continue skips to the next iteration. These statements are useful but should not replace a clear loop condition.
9. Runtime Errors and DebuggingA syntax error prevents JavaScript from being parsed. Examples include an unmatched brace or invalid keyword placement. A ReferenceError occurs when code uses an undeclared name. A TypeError occurs when an operation is invalid for a value, such as calling a non-function. A RangeError can occur when a value lies outside an accepted range or recursion becomes too deep. Example: const user = null;
console.log(user.name); // TypeError Debugging is a systematic process: - Read the error type and message.
- Inspect the file name and line number.
- Reproduce the problem with the smallest relevant input.
- Check variable values using
console.log or breakpoints. - Form a hypothesis and change one factor at a time.
- Retest both the failing case and normal cases.
The browser’s Sources or Debugger panel supports breakpoints, step-by-step execution, scope inspection, and call-stack analysis. An error message should be interpreted as evidence about program state, not merely suppressed. 10. Applied Case: Validating a Registration FormBackgroundConsider an illustrative registration page requiring a username, age, and acceptance of terms. The interface should reject incomplete or invalid data before submission. ProblemForm controls provide strings, even when an input appears numeric. A program that compares the raw age string without conversion may produce confusing results. It must also distinguish an empty field from a valid value of zero and avoid trusting client-side validation for security. Approach"use strict";
function validateRegistration(username, ageText, acceptedTerms) {
const name = username.trim();
if (name.length === 0) {
return "Enter a username.";
}
if (ageText.trim() === "") {
return "Enter your age.";
}
const age = Number(ageText);
if (!Number.isInteger(age) || age < 13) {
return "Age must be a whole number of at least 13.";
}
if (!acceptedTerms) {
return "Accept the terms to continue.";
}
return "Valid registration.";
}The function trims text, explicitly converts the age, verifies that it is an integer, applies the age rule, and checks the Boolean terms value. It returns a message rather than directly manipulating the page, which makes the validation logic easier to test. Outcome and Learning PointsThe example demonstrates strict mode, constants, string methods, conversion, Boolean conditions, logical operators, and early returns. In a complete application, the server must repeat validation because client-side code can be altered or bypassed. User messages should be helpful without exposing sensitive implementation details. 11. Coding Conventions and Responsible PracticeReadable code uses consistent indentation, meaningful names, small functions, and comments that explain decisions rather than restating syntax. Avoid global variables, duplicated logic, unexplained “magic numbers,” and deeply nested conditionals. Use linting and formatting tools where available. Test ordinary, boundary, and invalid inputs. Never insert untrusted text into a page using innerHTML without appropriate sanitization; use textContent for plain text when possible. Do not place passwords, private keys, or secret API credentials in browser JavaScript. Browser code is visible to users. Modern JavaScript continues to evolve through ECMAScript standards. Modules, optional chaining (user?.profile?.name), nullish coalescing, and clearer collection methods are widely used, but new syntax should be adopted with regard to browser compatibility and project requirements. Chapter SummaryJavaScript executes behavior in web applications and can be embedded or loaded as a separate, deferred file. Strict mode detects several unsafe practices. Modern programs generally use const and let, understanding their block scope and reassignment rules. JavaScript values include primitive types and reference-based objects such as arrays. Operators form expressions for arithmetic, assignment, comparison, logic, and conditional selection. Explicit type conversion and strict equality reduce ambiguity, while awareness of truthy and falsy values prevents validation errors. if, switch, and loops implement decisions and repetition. Runtime errors such as ReferenceError and TypeError provide useful diagnostic information when investigated with developer tools. Clear naming, modular functions, validation, testing, and secure handling of untrusted data are essential professional practices. Key TermsStrict mode: A JavaScript execution mode that rejects or restricts several error-prone behaviors. Variable: A named binding that refers to a value. Constant: A const binding that cannot be reassigned. Scope: The region of a program in which a name can be accessed. Block scope: Scope created by a pair of braces for let and const declarations. Primitive: An immutable, non-object value such as a number or Boolean. Reference value: An object-based value accessed through a reference. Expression: Code that produces a value. Statement: A complete instruction or action in a program. Operator: A symbol or keyword that performs an operation. Type conversion: Changing a value from one data type to another. Truthy: A value treated as true in a Boolean context. Falsy: A value treated as false in a Boolean context. Short-circuit evaluation: Stopping logical evaluation when the result is already determined. Conditional statement: A structure that selects code based on a condition. Iteration: Repeated execution of a block of code. Runtime error: An error occurring while a program executes. ReferenceError: An error caused by using an unavailable or undeclared name. TypeError: An error caused by an invalid operation for a value’s type. Linting: Automated analysis that detects style problems and likely programming errors. Review QuestionsShort Answer Questions- What is the purpose of the
defer attribute on an external script? - Why is
const not an absolute guarantee that an object cannot change? - What is the difference between
=== and ==? - Name three falsy JavaScript values.
- What information can a runtime error message provide during debugging?
Long Answer Questions- Explain primitive and reference values, using assignments to demonstrate their different behavior.
- Describe explicit and implicit type conversion and explain why explicit conversion is usually preferable in form validation.
- Compare
for, while, for...of, and for...in loops and identify an appropriate use for each. - Explain strict mode, block scope, and the problems associated with accidental global variables.
- Describe a systematic debugging process for a JavaScript program that produces a
TypeError.
Analytical / Application Questions- Design validation logic for a form containing an email address, a quantity, and a required checkbox. Identify the conversions and boundary cases that must be handled.
- A program uses
const settings = { theme: "light" }; and later changes settings.theme to "dark". Explain why this is permitted and propose a strategy for preventing property mutation if required. - A loop never terminates and causes the browser tab to become unresponsive. Analyze the likely causes and describe how you would locate and correct the error using developer tools.
Multiple Choice Questions with AnswersQuestion 1Which declaration is normally preferred for a value that should not be reassigned? A. var B. let C. const D. static Correct Answer: C. const Question 2What does 5 === "5" evaluate to? A. true B. false C. 5 D. An exception Correct Answer: B. false Question 3Which value is falsy in JavaScript? A. [] B. {} C. "hello" D. 0 Correct Answer: D. 0 Question 4What does Number("42") produce? A. The number 42 B. The string "42" C. NaN D. undefined Correct Answer: A. The number 42 Question 5Which loop iterates directly over the values of an array? A. for...in B. for...of C. switch D. while...case Correct Answer: B. for...of Question 6What error commonly occurs when code tries to access a property through null? A. SyntaxError B. ReferenceError C. TypeError D. RangeError Correct Answer: C. TypeError Question 7What is the main effect of the defer attribute on an external script? A. It prevents the script from downloading B. It executes the script after HTML parsing C. It converts the script to CSS D. It runs the script before parsing begins Correct Answer: B. It executes the script after HTML parsing Question 8What does the remainder operator % return? A. The quotient of a division B. The remainder of a division C. The percentage formatted as text D. A Boolean result Correct Answer: B. The remainder of a division Question 9Which operator supplies a fallback only for null or undefined? A. || B. && C. ?? D. !! Correct Answer: C. ?? Question 10Why should client-side form validation be repeated on the server? A. Browser JavaScript cannot display messages B. Client-side code can be modified or bypassed C. Server code always runs faster D. HTML forms cannot submit strings Correct Answer: B. Client-side code can be modified or bypassed
|