Skip to content

Variables

A variable is a region in memory where values can be stored for use in an application. Variables are a fundamental building block in any programming language, and JavaScript is no exception. In this module, you will learn about different types of variables, how to declare and assign values to them, and how to modify and use these values in your program. You will also be introduced to concepts such as scope and data types, which are crucial when working with variables in JavaScript.

Loosely-Typed

JavaScript is a loosely-typed (or dynamically-typed) language, meaning you don’t need to declare the type of a variable when you create it. The JavaScript engine automatically determines the type based on the value you assign.

But internally, JavaScript recognizes these primitive types:

  • string - Text values
  • number - Numeric values
  • boolean - true/false values
  • object - Complex data structures
  • null - Intentional absence of value
  • undefined - Variable declared but not assigned
  • symbol - Unique identifiers (advanced)
Understanding Loosely Typed vs. Statically Typed Languages

Loosely Typed Languages

  • Definition: In loosely typed languages, also known as dynamically typed languages, you don’t have to explicitly declare the data type of a variable. The language automatically determines the data type based on the assigned value.
  • Examples: JavaScript, Python, and Ruby.
  • Characteristics:
  • Flexibility in variable usage.
  • Easier for beginners due to fewer rules for variable declaration.
  • Potential for type-related errors at runtime, as type checking happens during execution.

Example in JavaScript:

let data = 20;       // data is a number
data = "Hello";      // now data is a string

Statically Typed Languages

  • Definition: In statically typed languages, you must declare the data type of a variable at the time of its declaration, and this type cannot be changed later.
  • Examples: Java, C#, and C++.
  • Characteristics:
  • Requires explicit declaration of variable types.
  • Can catch type-related errors at compile-time, leading to potentially fewer runtime errors.
  • Offers performance optimizations as the compiler knows the exact data types used.

Example in Java:

int number = 5;      // number must always be an integer
// number = "Hello"; // Error: incompatible types

Key Differences:

  1. Type Declaration: Loosely typed languages do not require explicit type declaration, whereas statically typed languages do.
  2. Error Detection: Statically typed languages can catch type errors at compile-time, while loosely typed languages catch these errors at runtime.
  3. Flexibility vs. Safety: Loosely typed languages offer more flexibility in using variables, but statically typed languages provide more safety against type-related runtime errors.

Understanding these differences is crucial for programming, as it influences the behavior of variables and error handling in your code.

Declaration: var, let, and const

JavaScript provides three ways to declare variables: var, let, and const.

Modern JavaScript: let and const

In modern JavaScript (ES6+), you should primarily use let and const:

let - For variables that will change:

let name = "Alice";
name = "Bob";  // ✅ Allowed
console.log(name);  // Bob

const - For variables that won’t be reassigned:

const age = 25;
// age = 26;  // ❌ Error: Assignment to constant variable

const Does NOT Mean Immutable

const prevents reassignment of the variable, but if the value is an object or array, you can still modify its contents:

const person = { name: "Alice" };
person.name = "Bob";  // ✅ Allowed - modifying property
console.log(person);  // { name: "Bob" }

// person = { name: "Charlie" };  // ❌ Error - can't reassign

const numbers = [1, 2, 3];
numbers.push(4);  // ✅ Allowed - modifying array
console.log(numbers);  // [1, 2, 3, 4]

// numbers = [5, 6, 7];  // ❌ Error - can't reassign

Legacy: var

The older var keyword should generally be avoided in modern code:

var oldStyle = "This is the old way";

Why avoid var?

  • Function-scoped instead of block-scoped (confusing behavior)
  • Can be redeclared accidentally
  • Hoisted to the top of the scope

You’ll see var in older code, but use let and const in new projects.

Scope: Block vs. Function

Block scope (applies to let and const):

if (true) {
  let blockScoped = "Only available in this block";
  console.log(blockScoped);  // Works
}
// console.log(blockScoped);  // ❌ Error: not defined

if (true) {
  const age = 25;
  console.log(age);  // 25
}
// console.log(age);  // ❌ Error: not defined

Function scope (applies to var):

function example() {
  if (true) {
    var functionScoped = "Available anywhere in the function";
  }
  console.log(functionScoped);  // Works (confusing!)
}

Block and Function Scope in JavaScript

JavaScript distinguishes between two types of scopes: block scope and function scope. Block scope is created within curly braces ({}) and is used with let and const declarations, limiting the visibility of a variable to within that block. Function scope, on the other hand, is defined within functions and is applied to variables declared with var, making them accessible anywhere within the function. Understanding these scopes is crucial for managing variable visibility and lifecycle, and avoiding unintended side effects or errors in your code.

Strict Mode in ES Modules

ES Modules Are Automatically Strict

When using ES Modules (which we use in this course), strict mode is automatically enabled. You don’t need to add "use strict"; manually.

Strict mode prevents common mistakes like:

// This would cause an error in strict mode
// undeclaredVariable = 5;  // ❌ Error: undeclaredVariable is not defined

// Always declare your variables
let declaredVariable = 5;  // ✅ Correct

Type Checking

You can check the type of a variable using typeof:

let i = 1;
console.log(typeof i);  // "number"

i = true;
console.log(typeof i);  // "boolean"

i = "hello";
console.log(typeof i);  // "string"

i = {};
console.log(typeof i);  // "object"

i = new Date();
console.log(typeof i);  // "object"
console.log(i instanceof Date);  // true

For more specific type checking with objects, use instanceof:

const date = new Date();
console.log(date instanceof Date);  // true
console.log(date instanceof Object);  // true

The Number Type

JavaScript uses 64-bit floating point numbers for all numeric values. This means there’s only one number type (unlike languages with int, float, double, etc.).

Basic Number Usage

let age = 25;
let price = 99.99;
let negative = -42;
let scientific = 3.14e5;  // 314000

console.log(age);        // 25
console.log(price);      // 99.99
console.log(scientific); // 314000

Number Precision and Limits

Numbers use . as the decimal point:

let precise = 100.23;
console.log(precise);  // 100.23

Very large numbers become Infinity:

let tooLarge = Math.pow(11, 308);
console.log(tooLarge);  // Infinity

Invalid calculations result in NaN (Not a Number):

let invalid = 0 / 0;
console.log(invalid);  // NaN

console.log(isNaN(invalid));  // true
console.log(isNaN(42));       // false

Number Methods

JavaScript provides several useful methods for formatting numbers:

let value = 2342.23342234;

console.log(value);                    // 2342.23342234
console.log(value.toFixed(2));         // "2342.23"
console.log(value.toString());         // "2342.23342234"
console.log(value.toLocaleString("da-DK"));  // "2.342,233" (Danish format)
console.log(
  value.toLocaleString("da-DK", {
    maximumFractionDigits: 2,
  })
);  // "2.342,23"

The Math Object

JavaScript provides a built-in Math object with properties and methods for mathematical constants and functions:

Rounding Numbers:

let number = 4.7;
console.log(Math.round(number));  // 5
console.log(Math.floor(number));  // 4
console.log(Math.ceil(number));   // 5

Generating Random Numbers:

let random = Math.random();  // Between 0 (inclusive) and 1 (exclusive)
console.log(random);

// Random integer between 1 and 10
let randomInt = Math.floor(Math.random() * 10) + 1;
console.log(randomInt);

Finding Maximum and Minimum:

console.log(Math.max(1, 5, 3, 7));  // 7
console.log(Math.min(1, 5, 3, 7));  // 1

Power and Square Roots:

console.log(Math.pow(2, 3));  // 8 (2 raised to the power of 3)
console.log(Math.sqrt(16));   // 4 (square root of 16)
console.log(Math.abs(-5));    // 5 (absolute value)

Type Conversion: String to Number

Sometimes you need to convert a string to a number. JavaScript provides several methods:

Using parseInt (for integers):

let strInt = "123";
console.log(parseInt(strInt));  // 123

let strFloat = "123.45";
console.log(parseInt(strFloat));  // 123 (only integer part)

let withText = "123px";
console.log(parseInt(withText));  // 123 (stops at first non-digit)

Using parseFloat (for decimal numbers):

let strInt = "123";
console.log(parseFloat(strInt));  // 123

let strFloat = "123.45";
console.log(parseFloat(strFloat));  // 123.45

let withText = "123.45px";
console.log(parseFloat(withText));  // 123.45

Using the Number Constructor:

let strNumber = "456";
console.log(Number(strNumber));  // 456

let invalidStr = "456abc";
console.log(Number(invalidStr));  // NaN (more strict than parseInt)

Unary + Operator (quickest way):

let strNum = "789";
console.log(+strNum);  // 789

let strFloatNum = "789.01";
console.log(+strFloatNum);  // 789.01

Bitwise OR | Operator (converts to integer):

let strBitwise = "234";
console.log(strBitwise | 0);  // 234

let strBitwiseFloat = "234.56";
console.log(strBitwiseFloat | 0);  // 234

Using Number.parseInt and Number.parseFloat:

These are essentially the same as global parseInt and parseFloat:

let strParseInt = "345";
console.log(Number.parseInt(strParseInt));  // 345

let strParseFloat = "345.67";
console.log(Number.parseFloat(strParseFloat));  // 345.67

Which Method to Use?

  • Use parseInt() or parseFloat() when parsing user input that might contain text
  • Use Number() or + when you want strict conversion (returns NaN if invalid)
  • Use parseInt() with a radix parameter for safety: parseInt("10", 10)

Number Operators

Operator Description
+ Addition
- Subtraction
* Multiplication
/ Division
% Modulus (Remainder after division)
++ Increment (Increases the value by 1)
-- Decrement (Decreases the value by 1)
** Exponentiation (ES2016)
let a = 10;
let b = 3;

console.log(a + b);   // 13
console.log(a - b);   // 7
console.log(a * b);   // 30
console.log(a / b);   // 3.3333...
console.log(a % b);   // 1 (remainder)
console.log(a ** b);  // 1000 (10^3)

a++;  // a is now 11
b--;  // b is now 2

Number System Issues

In JavaScript, how you write a number can cause it to be interpreted in different bases like octal (base 8) or hexadecimal (base 16).

Hexadecimal Numbers (base 16) start with 0x:

let hexNum = 0x1A;
console.log(hexNum);  // 26

Octal Numbers (base 8) can be written with 0o prefix:

let octalNum = 0o12;
console.log(octalNum);  // 10

Binary Numbers (base 2) use 0b prefix:

let binaryNum = 0b1010;
console.log(binaryNum);  // 10

Avoid Leading Zeros

In older JavaScript (ES5), numbers with leading zeros were interpreted as octal:

// In old JS: 012 would be interpreted as octal (value 10)
// In modern ES6+: This is an error

Always use explicit prefixes (0x, 0o, 0b) to avoid confusion.

BigInt for Very Large Numbers

BigInt is a newer data type for handling integers larger than 2^53 - 1 (the maximum safe integer for regular numbers). This is useful for cryptography, timestamps, or large database IDs.

// Regular number limit
const maxSafe = Number.MAX_SAFE_INTEGER;
console.log(maxSafe);  // 9007199254740991

// Using BigInt (add 'n' suffix)
const bigNumber = 9007199254740991n;
const bigger = bigNumber + 1n;  // Must use 'n' for operations
console.log(bigger);  // 9007199254740992n

// Convert from regular number
const bigFromNumber = BigInt(123456789);
console.log(bigFromNumber);  // 123456789n

BigInt Limitations

  • Can’t mix BigInt with regular numbers: 1n + 1 will error
  • Not all browsers support BigInt yet (check compatibility)
  • Can’t use with Math object methods

The Boolean Type

Boolean values represent logical truth: true or false. Named after mathematician George Boole, booleans are fundamental to programming logic.

Basic Boolean Usage

let isStudent = true;
let isAdult = false;

if (isStudent) {
  console.log("Eligible for student discount");
}

if (!isAdult) {
  console.log("Parental consent required");
}

Truthy and Falsy Values

In JavaScript, every value has an inherent “truthiness” when evaluated in a boolean context (like if statements).

Falsy values (evaluate to false):

  • false
  • 0 and -0
  • "" (empty string)
  • null
  • undefined
  • NaN

Everything else is truthy, including:

  • '0' (string containing zero)
  • [] (empty array)
  • {} (empty object)
  • Any non-zero number
  • Any non-empty string
// Falsy examples
if (false) {
  // Won't execute
}

if (0) {
  // Won't execute
}

if ("") {
  // Won't execute
}

// Truthy examples
if ("0") {
  console.log("String '0' is truthy!");  // Executes
}

if ([]) {
  console.log("Empty array is truthy!");  // Executes
}

if ({}) {
  console.log("Empty object is truthy!");  // Executes
}

if (42) {
  console.log("42 is truthy!");  // Executes
}

Using Double NOT (!!) to Test Truthiness

Use !! to convert any value to its boolean equivalent:

console.log(!!'hello');  // true
console.log(!!42);       // true
console.log(!![]);       // true
console.log(!!{});       // true

console.log(!!'');       // false
console.log(!!0);        // false
console.log(!!null);     // false
console.log(!!undefined);  // false
console.log(!!NaN);      // false

Comparison Operators

Always use === or !== for comparisons:

let a = 1;
let b = "1";

// Loose equality (performs type conversion) - AVOID
if (a == b) {
  console.log("1 == '1' is true - but confusing!");
}

// Strict equality (checks type first) - RECOMMENDED
if (a === b) {
  console.log("This won't execute - different types");
}

// Correct strict comparison
if (a === 1) {
  console.log("a is the number 1");
}

Avoid == and !=

The loose equality operators (== and !=) perform type conversion, leading to unexpected results:

console.log(0 == false);    // true (confusing!)
console.log('' == false);   // true (confusing!)
console.log(null == undefined);  // true (confusing!)

// Always use strict equality
console.log(0 === false);   // false (correct)
console.log('' === false);  // false (correct)
console.log(null === undefined);  // false (correct)

Boolean Operators

Operator Description
< Less than
> Greater than
<= Less than or equal to
>= Greater than or equal to
=== Strict equality (recommended)
!== Strict inequality (recommended)
! Logical NOT (Inversion)
&& Logical AND
| | Logical OR
let age = 25;

if (age >= 18 && age < 65) {
  console.log("Working age");
}

let hasLicense = true;
let hasInsurance = false;

if (hasLicense && hasInsurance) {
  console.log("Can drive");
} else {
  console.log("Cannot drive");
}

// Logical OR
if (age < 18 || age > 65) {
  console.log("Discount eligible");
}

// Logical NOT
if (!hasInsurance) {
  console.log("Need to buy insurance");
}

The String Type

Strings contain Unicode text and are one of the most commonly used data types in JavaScript.

Creating Strings

Use single quotes ('), double quotes ("), or backticks (`) for template literals:

let single = 'Hello';
let double = "World";
let template = `Hello, World!`;

// All three are valid - choose a style and be consistent

String Concatenation

Combine strings with the + operator:

let firstName = "Alice";
let lastName = "Johnson";
let fullName = firstName + " " + lastName;
console.log(fullName);  // "Alice Johnson"

Escape Characters

Special characters need to be escaped with backslash (\):

  • \n - Newline
  • \t - Tab
  • \' - Single quote
  • \" - Double quote
  • \\ - Backslash
  • \uNNNN - Unicode character
let text = "Line 1\nLine 2";
console.log(text);
// Line 1
// Line 2

let quote = "He said, \"Hello!\"";
console.log(quote);  // He said, "Hello!"

let path = "C:\\Users\\Alice\\Documents";
console.log(path);  // C:\Users\Alice\Documents

String Methods

JavaScript strings have many built-in methods:

let txt = "Marx Brothers";

console.log(txt.length);          // 13
console.log(txt.toUpperCase());   // "MARX BROTHERS"
console.log(txt.toLowerCase());   // "marx brothers"
console.log(txt.split(" "));      // ["Marx", "Brothers"]
console.log(txt.substring(0, 4)); // "Marx"
console.log(txt.slice(0, -5));    // "Marx Bro"
console.log(txt.charAt(5));       // "B"

// Modern methods (ES6+)
console.log(txt.startsWith("Ma"));   // true
console.log(txt.endsWith("rs"));     // true
console.log(txt.includes("BRO"));    // false (case-sensitive)
console.log(txt.includes("Bro"));    // true
console.log(txt.repeat(2));          // "Marx BrothersMarx Brothers"

// Trimming whitespace
let messy = "  hello world  ";
console.log(messy.trim());        // "hello world"
console.log(messy.trimStart());   // "hello world  "
console.log(messy.trimEnd());     // "  hello world"

// Replacing text
let original = "Hello World";
console.log(original.replace("World", "JavaScript"));  // "Hello JavaScript"
console.log(original.replaceAll("l", "L"));  // "HeLLo WorLd" (ES2021)

Template Strings (Template Literals)

Template strings use backticks and allow embedded expressions with ${}:

let name = "Mathias";
let amount = 100;

// Old way (concatenation)
console.log(name + " has DKK " + amount);
// Mathias has DKK 100

// Modern way (template literal)
console.log(`${name} has DKK ${amount}`);
// Mathias has DKK 100

// Complex expressions
console.log(`${name} has DKK ${amount} and next month DKK ${amount * 2}`);
// Mathias has DKK 100 and next month DKK 200

// Multi-line strings
let message = `
  Hello ${name},
  Your balance is: ${amount}
  Thank you!
`;
console.log(message);

Advanced Example - HTML Generation:

function personHTML({ name, hobbies, job }) {
  return `<article class="person">
    <h3>${name}</h3>
    <div>
        <div>Hobbies:</div>
        <ul>
            ${hobbies.map((hobby) => `<li>${hobby}</li>`).join("")}
        </ul>
    </div>
    <p>Current job: ${job}</p>
 </article>`;
}

console.log(
  personHTML({
    name: "Mikkel",
    hobbies: ["Football", "Fitness"],
    job: "Carpenter",
  })
);

/*
<article class="person">
    <h3>Mikkel</h3>
    <div>
        <div>Hobbies:</div>
        <ul>
            <li>Football</li><li>Fitness</li>
        </ul>
    </div>
    <p>Current job: Carpenter</p>
 </article>
*/

String Manipulation Libraries

While JavaScript’s built-in string methods are powerful, some developers prefer using libraries for complex string operations.

The most popular string manipulation library is Lodash. It provides utility functions for common programming tasks, including extensive string manipulation.

To install Lodash:

npm install lodash

Using Lodash with ES Modules:

import _ from 'lodash';

let str = "hello world";
let capitalized = _.capitalize(str);
console.log(capitalized);  // "Hello world"

let camelCase = _.camelCase("hello world example");
console.log(camelCase);  // "helloWorldExample"

let snakeCase = _.snakeCase("hello world example");
console.log(snakeCase);  // "hello_world_example"

When to Use String Libraries

  • For simple string operations, use built-in methods
  • Use Lodash when working with complex transformations, data structures, or need cross-browser consistency
  • Lodash also provides utility functions for arrays, objects, and functions

The Date Type

JavaScript’s Date object represents dates and times. However, it has some quirks and limitations, which is why many developers use libraries like date-fns or Luxon for more robust date handling.

Moment.js is Legacy

Moment.js was very popular but is now in maintenance mode. The Moment.js team recommends using modern alternatives like date-fns, Luxon, or Day.js for new projects.

Creating Dates

// Current date and time
let now = new Date();
console.log(now.toLocaleString());  // "10/28/2025, 2:30:45 PM" (format depends on locale)

// Specific date from string
let d = new Date("2019-5-14 9:10");
console.log(d.toLocaleString());  // "5/14/2019, 9:10:00 AM"

// Specific date from numbers (year, month, day, hour, minute, second)
d = new Date(2019, 4, 14, 9, 10);  // Month is 0-indexed!
console.log(d.toLocaleString());  // "5/14/2019, 9:10:00 AM"

Months Are 0-Indexed!

JavaScript dates use 0-based indexing for months: - 0 = January - 1 = February - … - 11 = December

let christmas = new Date(2025, 11, 24);  // December 24, 2025
console.log(christmas.getMonth());  // 11 (not 12!)

let newYear = new Date(2025, 0, 1);  // January 1, 2025
console.log(newYear.getMonth());  // 0

This quirk traces back to JavaScript’s early design choices and can be confusing. Always remember: months start at 0, but days start at 1.

Getting Date Components

let d = new Date(2019, 4, 14, 9, 10, 30);

console.log(d.getFullYear());   // 2019
console.log(d.getMonth());      // 4 (May - remember 0-indexed!)
console.log(d.getDate());       // 14 (day of month)
console.log(d.getDay());        // 2 (Tuesday - 0=Sunday, 6=Saturday)
console.log(d.getHours());      // 9
console.log(d.getMinutes());    // 10
console.log(d.getSeconds());    // 30
console.log(d.getTime());       // Milliseconds since Jan 1, 1970

Setting Date Components

let d = new Date(2019, 4, 14);

d.setFullYear(2020);
d.setMonth(11);  // December
d.setDate(25);   // 25th
d.setHours(15);
d.setMinutes(30);

console.log(d.toLocaleString());  // "12/25/2020, 3:30:00 PM"

Date Arithmetic

Dates can overflow, which is sometimes useful:

let d = new Date(2019, 11, 31);  // December 31, 2019
d.setDate(d.getDate() + 1);      // Add one day
console.log(d.toLocaleString());  // "1/1/2020..." (automatically rolls over to new year)

// Month overflow example
let d2 = new Date(2019, 12, 24);  // Month 12 = January of next year!
console.log(d2.toLocaleString());  // "1/24/2020..." (January 24, 2020)

Formatting Dates

let now = new Date();

// Various formatting options
console.log(now.toString());           // Full string
console.log(now.toDateString());       // "Tue Oct 28 2025"
console.log(now.toTimeString());       // "14:30:45 GMT+0100 (CET)"
console.log(now.toISOString());        // "2025-10-28T13:30:45.123Z"
console.log(now.toLocaleString("da-DK"));  // "28.10.2025 14.30.45"
console.log(now.toLocaleString("en-US"));  // "10/28/2025, 2:30:45 PM"

// Custom formatting with options
console.log(now.toLocaleString("da-DK", {
  weekday: 'long',
  year: 'numeric',
  month: 'long',
  day: 'numeric'
}));
// "tirsdag den 28. oktober 2025"

Using date-fns Library (Modern Alternative)

For more robust date handling, use date-fns:

npm install date-fns
import { format, addDays, differenceInDays } from 'date-fns';
import { da } from 'date-fns/locale';

let now = new Date();

// Format dates easily
console.log(format(now, 'yyyy-MM-dd'));  // "2025-10-28"
console.log(format(now, 'dd MMMM yyyy', { locale: da }));  // "28 oktober 2025"

// Add days
let nextWeek = addDays(now, 7);
console.log(format(nextWeek, 'yyyy-MM-dd'));  // "2025-11-04"

// Calculate differences
let christmas = new Date(2025, 11, 24);
let daysUntil = differenceInDays(christmas, now);
console.log(`${daysUntil} days until Christmas`);

Why Use a Date Library?

  • Timezone handling: Native Date has limited timezone support
  • Clearer API: More intuitive methods than native Date
  • Formatting: Easy, consistent date formatting
  • Immutability: Libraries like date-fns don’t mutate dates
  • Reliability: Better handling of edge cases and locales

Assignment(s)