HTML, CSS, JavaScript Basics

Chapter 8
JavaScript Language Foundations

Bachelors Program in Full Stack Development
HTML, CSS, JavaScript Basics   •   Bachelor

JavaScript Language Foundations

Introduction and Context

JavaScript is a programming language used to add behavior, interactivity, validation, and data processing to web applications. Although it was first associated with browsers, modern JavaScript also runs on servers, desktop applications, mobile platforms, and development tools. In a full-stack development program, JavaScript connects the structure provided by HTML and the presentation provided by CSS with computational logic.

A JavaScript program consists of statements and expressions. A statement performs an action, while an expression produces a value. For example, `let total = 8 + 4;` is a declaration statement containing the expression `8 + 4`.

Learning Objectives

By the end of this chapter, you should be able to:

  • Describe how JavaScript code is executed.
  • Use identifiers, variables, constants, and comments correctly.
  • Distinguish JavaScript primitive and reference-oriented values.
  • Apply arithmetic, comparison, logical, assignment, and conditional operators.
  • Convert values explicitly and predict common coercion behavior.
  • Use expressions, conditional statements, and loops to solve elementary problems.
  • Explain strict mode and its effect on safer programming.
  • Evaluate simple programs systematically and identify common errors.

1. How JavaScript Executes

In a browser, JavaScript is usually encountered through a `<script>` element or a module. The browser loads the source, parses it, and executes it using a JavaScript engine. The engine converts source text into an internal representation and runs the resulting instructions. Modern engines use interpretation, compilation, and optimization together; therefore, it is more accurate to describe execution as a managed process rather than simply “line by line.”

For ordinary scripts, statements are generally executed in source order, but execution can be affected by function calls, conditions, loops, exceptions, and asynchronous operations. JavaScript uses a single main thread for typical page code. The event loop coordinates tasks such as user events, timers, and network callbacks, allowing the page to remain responsive. Asynchronous execution is beyond the main scope of this chapter, but the distinction is important: source order does not always equal completion order when asynchronous APIs are used.

A script can be placed in an HTML document as follows:

```html

<script src="app.js" defer></script>

```

The `defer` attribute allows the document to be parsed while the external script is downloaded; the script then runs after parsing and before the `DOMContentLoaded` event. Modules are also deferred by default:

```html

<script type="module" src="app.js"></script>

```

For beginner experiments, the browser console or a runtime such as Node.js can execute JavaScript directly.

2. Syntax, Statements, and Identifiers

JavaScript is case-sensitive: `score`, `Score`, and `SCORE` are different identifiers. Identifiers may contain letters, digits, underscores, and dollar signs, but they cannot begin with a digit. Reserved words such as `if`, `class`, and `return` cannot be used as ordinary variable names.

Whitespace and line breaks usually separate tokens but do not determine program meaning. Semicolons are often inserted automatically by the language, but explicit semicolons improve readability and reduce ambiguity. Comments document intent and are ignored during execution:

```js

// Single-line comment

/ Multi-line comment /

```

A useful style is to use `camelCase` for variables and functions, descriptive names, consistent indentation, and small statements with one clear purpose.

3. Variables, Constants, and Scope

A variable is a named binding to a value. Modern JavaScript provides `let` and `const`:

```js

let attempts = 1;

attempts = attempts + 1;

const taxRate = 0.15;

```

`let` permits reassignment, whereas `const` does not permit reassignment of its binding. A `const` object can still have its properties changed because the binding and the object’s contents are different concepts:

```js

const user = { name: "Amina" };

user.name = "Luis"; // permitted

// user = {}; // TypeError: reassignment is not permitted

```

A declaration without an initial value gives a `let` variable the value `undefined`:

```js

let response;

console.log(response); // undefined

```

`var` is an older declaration form. It is function-scoped rather than block-scoped and permits redeclaration, which can cause accidental errors. New code should normally prefer `const`, using `let` only where reassignment is required.

A block is code enclosed in braces. Variables declared with `let` and `const` are block-scoped:

```js

let outside = "visible";

if (true) {

let inside = "local";

console.log(outside); // visible

}

// console.log(inside); // ReferenceError

```

Scope determines where a name can be accessed. Restricting scope reduces unintended interaction between parts of a program.

4. Data Types and Values

JavaScript values are dynamically typed: a variable does not have a permanently fixed type, although each current value has a type. The `typeof` operator provides a useful, though not perfect, classification.

Primitive types

  • String: text, such as `"Full Stack"` or `'web'`.
  • Number: ordinary numeric values, including integers and floating-point values. JavaScript also includes `NaN`, positive and negative infinity, and `-0` within the Number category.
  • BigInt: integers larger than the safe precise range of Number, written with `n`, such as `9007199254740993n`.
  • Boolean: `true` or `false`.
  • Undefined: the value of an uninitialized binding or a missing property.
  • Null: an intentional absence of an object value.
  • Symbol: a unique identifier, commonly used as an object key.

Objects are non-primitive values. Arrays, functions, dates, and many other structures are objects. Objects can contain properties and methods:

```js

const course = {

title: "JavaScript",

credits: 3

};

const topics = ["variables", "loops"];

```

Primitive values are immutable. A string operation produces a new string rather than changing the original string. Objects are mutable unless a program or API prevents modification. Assignment of an object copies a reference to the same object:

```js

const first = { count: 1 };

const second = first;

second.count = 2;

console.log(first.count); // 2

```

The expression `typeof null` returns `"object"`, a historical language behavior. This does not mean that `null` is an ordinary object; it remains a distinct primitive value. For reliable array checking, use `Array.isArray(value)` rather than `typeof value`.

5. Operators and Expressions

An expression produces a value. Operators combine or transform values.

Arithmetic operators

The arithmetic operators are `+`, `-`, `*`, `/`, `%`, and ``. The remainder operator `%` gives the remainder after division. For example, `17 % 5` is `2`. Exponentiation is written `2 3`, which is `8`. Parentheses should be used when they clarify intended precedence:

```js

const average = (18 + 20 + 22) / 3; // 20

```

The `+` operator adds numbers but concatenates when at least one operand is a string after coercion:

```js

2 + 3 // 5

"2" + 3 // "23"

```

Assignment operators

`=`, `+=`, `-=`, `*=`, and `/=` assign values. The expression `score += 5` is equivalent to `score = score + 5`.

Comparison operators

`>`, `<`, `>=`, and `<=` compare ordered values. Equality should normally use strict operators:

  • `===` means equal value and equal type.
  • `!==` means not equal in value or type.

Thus, `5 === "5"` is `false`, while `5 == "5"` is `true` because loose equality performs coercion. Loose equality has complex rules and is generally avoided in introductory application code.

Logical operators

`&&` represents logical AND, `||` represents logical OR, and `!` represents logical NOT. JavaScript uses 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. These operators return operands, not necessarily Boolean values:

```js

const displayName = userName || "Guest";

```

The nullish coalescing operator `??` uses the right operand only when the left operand is `null` or `undefined`, preserving valid values such as `0` and an empty string.

The conditional, or ternary, operator selects one of two expressions:

```js

const status = score >= 50 ? "Pass" : "Fail";

```

6. Type Conversion and Coercion

Explicit conversion makes intent visible. Common conversions include:

```js

Number("42") // 42

Number("42.5") // 42.5

Number("hello") // NaN

String(42) // "42"

Boolean(0) // false

Boolean("text") // true

```

`Number("")` produces `0`, while `Number(" ")` also produces `0`; this may be undesirable when validating user input. `Number.isNaN(value)` checks whether a value is the special numeric value `NaN`. It does not first coerce strings, so `Number.isNaN("hello")` is `false`, whereas `Number.isNaN(Number("hello"))` is `true`.

For integer input, `Number.parseInt("18px", 10)` returns `18`; the radix argument documents base ten. `Number.parseFloat("3.14kg")` returns `3.14`. Parsing functions may accept a valid numeric prefix, so complete validation may require checking the original input as well.

Implicit coercion occurs in some operators. For example, `"6" * 2` produces `12`, while `"6" + 2` produces `"62"`. This difference is a common source of defects. A robust approach is to convert external input immediately, validate the result, and then perform calculations with known types.

Truthiness is relevant to conditions. Falsy values include `false`, `0`, `-0`, `NaN`, `""`, `null`, and `undefined`. Most other values, including empty arrays and empty objects, are truthy.

7. Conditional Execution

An `if` statement executes a block when its condition is truthy:

```js

if (temperature > 30) {

console.log("Hot");

} else if (temperature >= 18) {

console.log("Moderate");

} else {

console.log("Cool");

}

```

Conditions should express the business rule directly and should use strict comparisons where appropriate. A `switch` statement is useful when one expression is compared with several discrete values:

```js

switch (role) {

case "admin":

access = "full";

break;

case "editor":

access = "limited";

break;

default:

access = "none";

}

```

The `break` statements prevent fall-through into the next case. Without them, execution continues unless a return or another control transfer occurs.

8. Repetition with Loops

A `for` loop is appropriate when initialization, a continuation condition, and an update can be stated clearly:

```js

let total = 0;

for (let number = 1; number <= 5; number++) {

total += number;

}

// total is 15

```

A `while` loop is useful when repetition depends on a condition whose number of iterations is not known in advance:

```js

let attempts = 0;

while (attempts < 3) {

attempts++;

}

```

A `do...while` loop executes its body at least once. `break` exits a loop, while `continue` skips to the next iteration. Both should be used sparingly because excessive control transfer can make logic difficult to follow.

For arrays, `for...of` iterates over values:

```js

const marks = [60, 72, 81];

for (const mark of marks) {

console.log(mark);

}

```

`for...in` iterates over enumerable property names and is generally more suitable for object properties than array values.

9. Strict Mode

Strict mode enables additional error checking and changes certain unsafe behaviors. It is activated in a script or function with:

```js

"use strict";

```

In strict mode, assigning to an undeclared variable causes a `ReferenceError` instead of silently creating a global variable:

```js

"use strict";

count = 1; // ReferenceError

```

Strict mode also rejects some duplicate parameter and legacy syntax patterns and prevents certain accidental receiver behaviors in functions. JavaScript modules are automatically strict, so module-based applications receive these protections without the directive. Strict mode does not replace validation, testing, or secure design, but it helps expose programming mistakes early.

10. Worked Elementary Problems

Example 1: Validating and converting a score

Suppose a form supplies the text `"78"`. The program should accept scores from 0 through 100:

```js

const rawScore = "78";

const score = Number(rawScore);

if (!Number.isNaN(score) && score >= 0 && score <= 100) {

console.log(score >= 50 ? "Pass" : "Fail");

} else {

console.log("Invalid score");

}

```

Conversion occurs before comparison. The value is numeric, not a string, and the range condition excludes invalid scores. Since 78 is at least 50, the output is `Pass`.

Example 2: Calculating a cart total

```js

const prices = [12.50, 7.25, 10.00];

let total = 0;

for (const price of prices) {

total += price;

}

const delivery = total >= 25 ? 0 : 4.99;

const finalTotal = total + delivery;

console.log(finalTotal);

```

The item total is 12.50 + 7.25 + 10.00 = 29.75. Because this is at least 25, delivery is 0 and the final total is 29.75. In production financial systems, currency should be handled carefully, often by storing minor units such as cents as integers or using a suitable decimal library, because binary floating-point representation can produce small rounding artifacts.

Example 3: Counting positive values

```js

const values = [-2, 4, 0, 9, -1, 3];

let positiveCount = 0;

for (const value of values) {

if (value > 0) {

positiveCount++;

}

}

```

The positive values are 4, 9, and 3, so `positiveCount` becomes 3. Notice that zero is not positive.

11. Applied Case: A Course-Registration Form

Background

Consider an illustrative university course-registration form that receives a student’s requested credit load as text.

Problem

The system must convert the input, reject blank or invalid values, and classify the request as normal, overload, or invalid. Assume the institutional rules are: a valid load is from 1 through 18 credits; 19 through 24 credits requires overload review; values above 24 are rejected.

Analysis and solution

```js

"use strict";

function classifyCredits(rawInput) {

const text = String(rawInput).trim();

if (text === "") return "Invalid: enter a credit value";

const credits = Number(text);

if (!Number.isInteger(credits) || credits < 1) {

return "Invalid: credits must be a positive integer";

}

if (credits <= 18) return "Normal registration";

if (credits <= 24) return "Overload review required";

return "Invalid: credit limit exceeded";

}

```

For input `"15"`, conversion gives the integer 15 and the result is `Normal registration`. For `"21"`, the result is `Overload review required`. For `"abc"`, `Number` gives `NaN`; `Number.isInteger(NaN)` is false, so the input is rejected. The function also handles whitespace and avoids relying on implicit coercion.

Outcome and learning points

The solution separates conversion, validation, classification, and output. It uses strict mode, explicit conversion, a compound condition, and ordered conditional branches. In a real system, server-side validation must repeat these checks because browser-side JavaScript can be modified or bypassed.

12. Challenges, Limitations, and Best Practices

JavaScript’s flexibility supports rapid development but creates risks. Dynamic typing can permit incorrect values to travel through a program. Implicit coercion can produce surprising results. Floating-point numbers are not a perfect representation of all decimal fractions. Global variables, unclear names, and excessive nesting reduce maintainability.

Recommended practices include using `const` by default, using `let` only when reassignment is necessary, preferring `===` and `!==`, converting external input explicitly, validating both type and range, keeping loops bounded, and testing boundary cases such as zero, empty text, the minimum, and the maximum accepted value. Linters, formatters, browser developer tools, unit tests, and TypeScript can improve reliability, but they do not eliminate the need for sound reasoning.

Security is also relevant. Never treat client-side validation as authorization, and never insert untrusted text into HTML using unsafe APIs. JavaScript code should minimize unnecessary access to personal data and should follow institutional privacy and security policies. AI coding assistants may suggest syntax or tests, but developers remain responsible for checking generated code, especially its validation, security, and edge-case behavior.

Chapter Summary

JavaScript executes source code through an engine that parses, compiles, and runs statements, while browser event mechanisms can introduce asynchronous behavior. Variables are declared with `let` and `const`, and block scope limits accidental interaction. JavaScript includes primitive values such as strings, numbers, booleans, `undefined`, and `null`, as well as objects and arrays. Expressions use arithmetic, assignment, comparison, logical, and conditional operators.

Explicit type conversion is safer than relying on implicit coercion. Conditions select behavior, loops repeat behavior, and strict mode exposes undeclared-variable and related errors. Elementary solutions should convert and validate input, state boundary rules clearly, use appropriate control flow, and test normal and exceptional cases. These foundations support later work with functions, the DOM, events, asynchronous programming, APIs, and full-stack applications.

Key Terms

JavaScript: A programming language used for client-side and many server-side applications.

Statement: An instruction that performs an action.

Expression: Code that evaluates to a value.

Identifier: A name used for a variable, constant, function, or other program entity.

Variable: A named binding whose value may be reassigned.

Constant: A binding declared with `const` that cannot be reassigned.

Scope: The region in which an identifier can be accessed.

Primitive: An immutable, non-object value.

Object: A collection-based, non-primitive value with properties.

Type coercion: Automatic conversion of a value by JavaScript.

Explicit conversion: Deliberate conversion using operations such as `Number` or `String`.

Truthy: A value treated as true in a Boolean context.

Falsy: A value treated as false in a Boolean context.

Operator: A symbol or keyword that combines or transforms values.

Conditional: A construct that selects behavior based on a condition.

Iteration: Repeated execution of a block of code.

Strict mode: A JavaScript mode that applies additional error checking and safer rules.

NaN: A special numeric value meaning “not a number.”

Event loop: A mechanism that coordinates asynchronous callbacks with JavaScript execution.

Review Questions

Short Answer Questions

1. What is the difference between a statement and an expression?

2. How do `let` and `const` differ?

3. Why is `===` generally preferred to `==`?

4. Name three falsy JavaScript values.

5. What problem does strict mode help identify?

Long Answer Questions

1. Explain JavaScript’s main data types and distinguish primitive values from objects.

2. Describe explicit and implicit type conversion, using suitable examples.

3. Compare `if...else`, `switch`, `for`, and `while` constructs and state when each is useful.

4. Explain block scope and why modern JavaScript generally avoids `var`.

5. Discuss best practices for validating numerical input from a web form.

Analytical / Application Questions

1. Design an algorithm that reads a text input, converts it to a number, rejects invalid values, and classifies a temperature as cold, moderate, or hot. State your boundary conditions.

2. Trace a loop that sums all even integers from 2 through 10. Show the value of the accumulator after each iteration.

3. A program uses `if (input == 0)` to validate form data. Analyze at least two possible problems with this approach and propose a stricter alternative.

Multiple Choice Questions with Answers

Question 1

Which declaration prevents reassignment of its binding?

A. var

B. let

C. const

D. static

Correct Answer: C. const

Question 2

What is the result of the expression 5 === "5"?

A. true

B. false

C. 5

D. undefined

Correct Answer: B. false

Question 3

What value does Number("42") produce?

A. The string "42"

B. The number 42

C. The Boolean true

D. NaN

Correct Answer: B. The number 42

Question 4

Which operator returns the remainder after division?

A. //

B. %

C. **

D. &

Correct Answer: B. %

Question 5

What is the value of 17 % 5?

A. 2

B. 3

C. 5

D. 12

Correct Answer: A. 2

Question 6

Which loop is most directly suited to iterating over the values of an array?

A. for...of

B. for...in

C. switch

D. if...else

Correct Answer: A. for...of

Question 7

What does a break statement do inside a loop?

A. Skips only the current iteration

B. Restarts the loop

C. Exits the loop

D. Converts the loop value to Boolean

Correct Answer: C. Exits the loop

Question 8

Which value is falsy in a JavaScript condition?

A. []

B. {}

C. "text"

D. 0

Correct Answer: D. 0

Question 9

What happens in strict mode when code assigns to an undeclared variable?

A. A global variable is silently created

B. A ReferenceError is produced

C. The value becomes null

D. The assignment is ignored without notification

Correct Answer: B. A ReferenceError is produced

Question 10

What is the final total in the cart example when prices are 12.50, 7.25, and 10.00 and delivery is free above 25?

A. 25.00

B. 29.75

C. 34.74

D. 30.75

Correct Answer: B. 29.75

HTML, CSS, JavaScript Basics
Chapter 8 of 15