4.2: Variables, Data Types & Operators

Master JavaScript operators and control flow structures including conditionals and loops. Learn how to make decisions in code and execute repetitive tasks efficiently using if statements, switch cases, and various loop types.

1. Variables Deep Dive

Variable Scope

Block Scope (let and const):

{
  let x = 10;
  const y = 20;
  console.log(x, y);  // 10, 20
}
// console.log(x);  // Error: x is not defined

Function Scope (var):

function test() {
  var x = 10;
  if (true) {
    var y = 20;  // Same scope as x!
  }
  console.log(x, y);  // 10, 20 (y is accessible)
}
// console.log(x);  // Error: x is not defined

Python comparison:

def test():
    x = 10
    if True:
        y = 20
    print(x, y)  # Works - Python has function scope for variables

# print(x)  # Error: x not defined outside function

Hoisting

JavaScript "hoists" variable declarations to the top:

console.log(x);  // undefined (not error!)
var x = 5;

// What JavaScript actually does:
var x;
console.log(x);  // undefined
x = 5;

let and const are NOT hoisted:

// console.log(y);  // Error: Cannot access before initialization
let y = 5;

Best practice: Always declare variables at the top of their scope.

Temporal Dead Zone

{
  // TDZ for x starts here
  console.log(x);  // Error: Cannot access 'x' before initialization
  let x = 10;      // TDZ ends here
}

const with Objects

const prevents reassignment, but NOT mutation:

const user = { name: "Alice", age: 30 };

// user = {};  // Error: Cannot reassign

user.age = 31;       // OK: Mutating object
user.city = "NYC";   // OK: Adding property

console.log(user);   // { name: "Alice", age: 31, city: "NYC" }

Python comparison:

# Python has no true const, but convention uses UPPERCASE
USER = {"name": "Alice", "age": 30}
USER["age"] = 31  # Allowed - Python has no immutable dict by default

2. Number Type

Number Basics

JavaScript has one number type for integers and floats:

let integer = 42;
let float = 3.14;
let negative = -10;
let scientific = 2.5e6;  // 2,500,000

console.log(typeof integer);  // "number"
console.log(typeof float);    // "number"

Python comparison:

integer = 42        # int
float_num = 3.14    # float
# Different types!

Special Numeric Values

let infinity = Infinity;
let negInfinity = -Infinity;
let notNumber = NaN;  // Not a Number

console.log(1 / 0);        // Infinity
console.log(-1 / 0);       // -Infinity
console.log("hello" * 2);  // NaN

// Check for special values
console.log(isFinite(100));      // true
console.log(isFinite(Infinity)); // false
console.log(isNaN(NaN));         // true
console.log(isNaN("hello"));     // true

Number Precision

JavaScript uses 64-bit floating point (IEEE 754):

console.log(0.1 + 0.2);              // 0.30000000000004
console.log(0.1 + 0.2 === 0.3);      // false!

// Solution: Round or compare with epsilon
console.log((0.1 + 0.2).toFixed(1)); // "0.3"

Python has same issue:

0.1 + 0.2  # 0.30000000000000004

Number Methods

let num = 123.456;

num.toFixed(2);        // "123.46" (string!)
num.toPrecision(4);    // "123.5" (string!)
num.toString();        // "123.456" (string)

Number(num.toFixed(2)); // 123.46 (back to number)

Math Object

Math.PI;              // 3.141592653589793
Math.E;               // 2.718281828459045

Math.round(4.7);      // 5
Math.ceil(4.1);       // 5
Math.floor(4.9);      // 4
Math.trunc(4.9);      // 4 (removes decimal)

Math.abs(-5);         // 5
Math.pow(2, 3);       // 8
Math.sqrt(16);        // 4
Math.cbrt(27);        // 3 (cube root)

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

Math.random();        // Random between 0 and 1
Math.floor(Math.random() * 10);  // Random 0-9

Python comparison:

import math

math.pi              # 3.141592653589793
round(4.7)           # 5
math.ceil(4.1)       # 5
math.floor(4.9)      # 4
abs(-5)              # 5
pow(2, 3)            # 8 or 2**3
math.sqrt(16)        # 4.0
max(1, 5, 3)         # 5
min(1, 5, 3)         # 1

import random
random.random()      # Random 0-1

3. String Type

String Creation

let single = 'Single quotes';
let double = "Double quotes";
let backtick = `Template literal`;

// All create the same type
console.log(typeof single);  // "string"

String Concatenation

let first = "Hello";
let last = "World";

// Old way: concatenation
let greeting = first + " " + last;  // "Hello World"

// Modern way: template literals
let greeting2 = `${first} ${last}`;  // "Hello World"

Python comparison:

first = "Hello"
last = "World"

greeting = first + " " + last  # "Hello World"
greeting = f"{first} {last}"   # f-string (like template literals)

Template Literals

let name = "Alice";
let age = 30;

// Multi-line strings
let message = `
  Hello ${name}!
  You are ${age} years old.
  Next year you'll be ${age + 1}.
`;

// Expressions in template literals
let price = 19.99;
let tax = 0.08;
console.log(`Total: $${(price * (1 + tax)).toFixed(2)}`);  // Total: $21.59

Python comparison:

name = "Alice"
age = 30

# Multi-line f-string
message = f"""
  Hello {name}!
  You are {age} years old.
  Next year you'll be {age + 1}.
"""

String Properties and Methods

let text = "JavaScript";

// Property
text.length;  // 10

// Methods (immutable - return new string)
text.toUpperCase();         // "JAVASCRIPT"
text.toLowerCase();         // "javascript"
text.charAt(0);             // "J"
text[0];                    // "J" (array-like access)
text.indexOf("Script");     // 4
text.lastIndexOf("a");      // 3
text.includes("Script");    // true
text.startsWith("Java");    // true
text.endsWith("Script");    // true
text.slice(0, 4);           // "Java"
text.slice(-6);             // "Script"
text.substring(4, 10);      // "Script"
text.replace("Java", "Type"); // "TypeScript"
text.replaceAll("a", "A");  // "JAvAScript"
text.trim();                // Remove whitespace
text.split("");             // ["J", "a", "v", "a", ...]
text.repeat(2);             // "JavaScriptJavaScript"

Python comparison:

text = "JavaScript"

len(text)                # 10
text.upper()             # "JAVASCRIPT"
text.lower()             # "javascript"
text[0]                  # "J"
text.index("Script")     # 4
"Script" in text         # True
text.startswith("Java")  # True
text.endswith("Script")  # True
text[0:4]                # "Java"
text[-6:]                # "Script"
text.replace("Java", "Type")  # "TypeScript"
text.strip()             # Remove whitespace
text.split("")           # Error: empty separator
list(text)               # ["J", "a", "v", "a", ...]

String Immutability

let str = "Hello";
str[0] = "h";        // No effect - strings are immutable
console.log(str);    // "Hello"

// Must create new string
str = "h" + str.slice(1);  // "hello"

Same in Python:

str = "Hello"
# str[0] = "h"  # Error: strings are immutable
str = "h" + str[1:]  # "hello"

4. Boolean Type

Boolean Values

let isTrue = true;
let isFalse = false;

console.log(typeof isTrue);  // "boolean"

Python:

is_true = True   # Capitalized
is_false = False

Truthy and Falsy

Falsy values (evaluate to false):

Boolean(false);      // false
Boolean(0);          // false
Boolean(-0);         // false
Boolean(0n);         // false (BigInt zero)
Boolean("");         // false (empty string)
Boolean(null);       // false
Boolean(undefined);  // false
Boolean(NaN);        // false

Everything else is truthy:

Boolean(true);       // true
Boolean(1);          // true
Boolean(-1);         // true
Boolean("0");        // true (string "0", not number 0)
Boolean("false");    // true (any non-empty string)
Boolean([]);         // true (empty array)
Boolean({});         // true (empty object)
Boolean(function(){});  // true

Python comparison:

# Falsy: False, 0, 0.0, "", [], {}, None
bool([])   # False (different from JavaScript!)
bool({})   # False

Boolean Conversion

// Explicit conversion
Boolean(1);          // true
Boolean(0);          // false

// Implicit conversion (in conditionals)
if (1) {
  console.log("Truthy!");  // Runs
}

if ("") {
  console.log("Won't run");
}

// Double negation (common trick)
let hasValue = !!"hello";  // true
let isEmpty = !!"";        // false

5. Null and Undefined

Undefined

Undefined means "no value assigned":

let x;
console.log(x);  // undefined

function test() {}
console.log(test());  // undefined (no return)

let obj = {};
console.log(obj.nonExistent);  // undefined

Null

Null means "intentionally empty":

let empty = null;  // Explicitly set to nothing

let user = null;   // User not logged in
if (user === null) {
  console.log("Please log in");
}

Null vs Undefined

typeof undefined;  // "undefined"
typeof null;       // "object" (JavaScript bug!)

null === undefined;     // false
null == undefined;      // true (loose equality)

// Best practice: use null for intentional absence
let user = null;         // Not logged in (intentional)
let result;              // undefined (uninitialized)

Python comparison:

# Python only has None (similar to null)
user = None

if user is None:
    print("Not logged in")

6. Type Conversion

Explicit Conversion

To String:

String(123);         // "123"
String(true);        // "true"
String(null);        // "null"
String(undefined);   // "undefined"

(123).toString();    // "123"
true.toString();     // "true"

To Number:

Number("123");       // 123
Number("12.5");      // 12.5
Number("hello");     // NaN
Number(true);        // 1
Number(false);       // 0
Number(null);        // 0
Number(undefined);   // NaN
Number("");          // 0 (empty string!)

parseInt("123");     // 123
parseInt("123.45");  // 123 (truncates)
parseFloat("123.45"); // 123.45
parseInt("123px");   // 123 (stops at non-digit)

To Boolean:

Boolean(1);          // true
Boolean(0);          // false
Boolean("hello");    // true
Boolean("");         // false

// Double negation trick
!!"hello";           // true
!!0;                 // false

Python comparison:

str(123)           # "123"
int("123")         # 123
float("123.45")    # 123.45
bool(1)            # True
bool(0)            # False
# int("123px")     # Error (Python is stricter)

Implicit Conversion (Coercion)

String coercion:

"3" + 2;        // "32" (number → string)
"3" + 2 + 1;    // "321"
2 + 1 + "3";    // "33"

Number coercion:

"3" - 2;        // 1 (string → number)
"3" * "2";      // 6
"6" / "2";      // 3
"5" - true;     // 4 (true → 1)

Boolean coercion:

if ("hello") {   // "hello" → true
  console.log("Truthy");
}

let x = 5 || 10;      // 5 (first truthy value)
let y = 0 || 10;      // 10
let z = null ?? 10;   // 10 (nullish coalescing)

7. Operators

Arithmetic Operators

10 + 5;    // 15 (addition)
10 - 5;    // 5 (subtraction)
10 * 5;    // 50 (multiplication)
10 / 5;    // 2 (division)
10 % 3;    // 1 (remainder/modulo)
10 ** 2;   // 100 (exponentiation)

// Increment/Decrement
let x = 5;
x++;       // 6 (post-increment)
++x;       // 7 (pre-increment)
x--;       // 6 (post-decrement)
--x;       // 5 (pre-decrement)

Assignment Operators

let x = 10;

x += 5;    // x = x + 5 → 15
x -= 3;    // x = x - 3 → 12
x *= 2;    // x = x * 2 → 24
x /= 4;    // x = x / 4 → 6
x %= 4;    // x = x % 4 → 2
x **= 3;   // x = x ** 3 → 8

Python has same:

x = 10
x += 5     # 15
x -= 3     # 12
# etc.

Comparison Operators

// Strict equality (use these!)
5 === 5;        // true
5 === "5";      // false
5 !== "5";      // true

// Loose equality (avoid!)
5 == "5";       // true (type coercion)
0 == false;     // true
"" == false;    // true
null == undefined; // true

// Relational
5 > 3;          // true
5 < 3;          // false
5 >= 5;         // true
5 <= 4;         // false

Logical Operators

// AND (&&)
true && true;    // true
true && false;   // false

// OR (||)
true || false;   // true
false || false;  // false

// NOT (!)
!true;           // false
!false;          // true

// Short-circuit evaluation
let x = 0 || 10;        // 10 (0 is falsy)
let y = 5 || 10;        // 5 (first truthy)
let z = 5 && 10;        // 10 (last truthy)
let a = 0 && 10;        // 0 (first falsy)

Python:

# and, or, not (keywords)
True and True    # True
True or False    # True
not True         # False

Nullish Coalescing (??)

// Returns right side if left is null/undefined
let x = null ?? 10;       // 10
let y = undefined ?? 10;  // 10
let z = 0 ?? 10;          // 0 (0 is not null/undefined)
let a = "" ?? "default";  // "" (empty string is not null/undefined)

// Compare to ||
let b = 0 || 10;          // 10 (0 is falsy)
let c = 0 ?? 10;          // 0 (0 is not null/undefined)

Ternary Operator

// condition ? valueIfTrue : valueIfFalse
let age = 18;
let status = age >= 18 ? "Adult" : "Minor";  // "Adult"

// Nested ternary (use sparingly)
let grade = score >= 90 ? "A" :
            score >= 80 ? "B" :
            score >= 70 ? "C" : "F";

Python:

age = 18
status = "Adult" if age >= 18 else "Minor"

Operator Precedence

From highest to lowest:

// 1. Grouping ()
(2 + 3) * 4;  // 20

// 2. Member access, function call
obj.prop
func()

// 3. Exponentiation **
2 ** 3;  // 8

// 4. Unary + - ! typeof
!true

// 5. Multiplication * / %
2 * 3 + 4;  // 10

// 6. Addition + -
2 + 3 * 4;  // 14

// 7. Comparison < <= > >=
5 > 3 && 2 < 4;  // true

// 8. Equality == === != !==
5 === 5 && 3 === 3;  // true

// 9. Logical AND &&
true && false || true;  // true

// 10. Logical OR ||
false || false && true;  // false

// 11. Assignment = += -= etc
let x = 5 + 3;  // Assignment last

Use parentheses for clarity:

// Unclear
let result = 2 + 3 * 4 ** 2;  // ?

// Clear
let result = 2 + (3 * (4 ** 2));  // 50

8. Practical Examples

Example 1: Temperature Converter

function celsiusToFahrenheit(celsius) {
  return (celsius * 9/5) + 32;
}

function fahrenheitToCelsius(fahrenheit) {
  return (fahrenheit - 32) * 5/9;
}

console.log(celsiusToFahrenheit(0));   // 32
console.log(celsiusToFahrenheit(100)); // 212
console.log(fahrenheitToCelsius(32));  // 0

Example 2: String Formatter

function formatName(firstName, lastName) {
  const full = `${firstName} ${lastName}`;
  return {
    full: full,
    uppercase: full.toUpperCase(),
    lowercase: full.toLowerCase(),
    initials: `${firstName[0]}${lastName[0]}`.toUpperCase()
  };
}

console.log(formatName("john", "doe"));
// {
//   full: "john doe",
//   uppercase: "JOHN DOE",
//   lowercase: "john doe",
//   initials: "JD"
// }

Example 3: Safe Division

function safeDivide(a, b) {
  if (b === 0) {
    return "Cannot divide by zero";
  }
  return a / b;
}

console.log(safeDivide(10, 2));  // 5
console.log(safeDivide(10, 0));  // "Cannot divide by zero"

Example 4: Type Checker

function getType(value) {
  if (value === null) return "null";
  if (Array.isArray(value)) return "array";
  return typeof value;
}

console.log(getType(42));          // "number"
console.log(getType("hello"));     // "string"
console.log(getType(null));        // "null"
console.log(getType([1, 2, 3]));   // "array"

9. Practical Exercises

Exercise 4.2.1: Variable Scope

Create examples demonstrating:

  1. Block scope with let and const
  2. Function scope with var
  3. Why const can't prevent object mutation

Exercise 4.2.2: Type Conversion Challenge

Write functions to:

  1. Safely convert string to number (return NaN if invalid)
  2. Convert any value to boolean
  3. Format numbers to 2 decimal places

Exercise 4.2.3: String Manipulation

Create a function that:

  1. Takes a full name (e.g., "john doe")
  2. Returns title case (e.g., "John Doe")
  3. Handles multiple spaces
  4. Works with hyphenated names (e.g., "jean-paul sartre")

Exercise 4.2.4: Calculator

Build a calculator function that:

  1. Takes operator (+, -, *, /, **, %)
  2. Takes two numbers
  3. Returns result or error message
  4. Handles division by zero

10. Knowledge Check

Question 1: What's the difference between null and undefined?

Show answer `undefined` means a variable has been declared but not assigned. `null` is an intentional absence of value. Use `null` to explicitly indicate "no value".

Question 2: Why does typeof null return "object"?

Show answer This is a JavaScript bug from the original implementation that can't be fixed for backward compatibility reasons.

Question 3: What's the difference between == and ===?

Show answer `==` performs type coercion (5 == "5" is true). `===` checks type AND value (5 === "5" is false). Always use `===`.

Question 4: What are falsy values in JavaScript?

Show answer false, 0, -0, 0n, "" (empty string), null, undefined, NaN. Everything else is truthy, including "0", "false", [], {}.

Question 5: What does 0.1 + 0.2 === 0.3 return and why?

Show answer Returns `false`. JavaScript uses IEEE 754 floating point, which has precision issues: 0.1 + 0.2 = 0.30000000000004.

Question 6: What's the difference between || and ???

Show answer `||` returns first truthy value. `??` (nullish coalescing) only checks for null/undefined. `0 || 10` returns 10, but `0 ?? 10` returns 0.

11. Key Takeaways

  • Use const by default, let for reassignment, never var
  • let and const are block-scoped, var is function-scoped
  • JavaScript has one number type for integers and floats
  • Strings are immutable and have many useful methods
  • Template literals `${expr}` are like Python f-strings
  • Falsy values: false, 0, "", null, undefined, NaN (everything else is truthy)
  • null is intentional absence, undefined is unassigned
  • Always use === (strict equality), not ==
  • Type coercion happens automatically (especially with +)
  • ?? (nullish coalescing) is safer than || for default values
  • Use typeof for type checking (but it returns "object" for null and arrays)

12. Further Resources

Documentation:

Tools:


Next Steps

Great work! You now understand JavaScript's type system and operators in depth.

In Lesson 4.3: Functions & Scope, you'll learn how to write functions in JavaScript, understand scope and closures, and explore arrow functions and higher-order functions.

Next: Lesson 4.3 - Functions & Scope →