Introduction to JavaScript · Lesson 1 of 5
Variables, Types & Functions
JavaScript Variables, Types, and Functions
JavaScript is the language of the web. Every interactive website, web app, and Node.js server is built on it. This lesson covers the core building blocks you'll use in every JS file you ever write.
Declaring Variables: var, let, const
JavaScript has three ways to declare a variable. You'll use let and const almost exclusively in modern code.
// const — value cannot be reassigned (use this by default)
const name = "Asma";
const PI = 3.14159;
// let — value can be reassigned (use when you need to change the value)
let score = 0;
score = 10; // fine
// var — old, function-scoped, avoid in new code
var oldStyle = "don't use this";Rule of thumb: Start with const. If you need to reassign later, change it to let. Never use var.
Data Types
JavaScript has 7 primitive types and 1 object type:
// String
const greeting = "Hello";
const name = 'World';
const template = `Hello, ${name}!`; // template literal
// Number (integers AND floats are both "number")
const age = 25;
const price = 19.99;
const negative = -10;
const notANumber = NaN; // result of invalid math
const infinite = Infinity; // result of dividing by zero
// Boolean
const isActive = true;
const isDeleted = false;
// null — intentional absence of value
const user = null;
// undefined — variable declared but not assigned
let unset;
console.log(unset); // undefined
// Symbol — unique identifier (advanced)
const id = Symbol("id");
// BigInt — integers beyond Number.MAX_SAFE_INTEGER
const bigNum = 9007199254740991n;typeof
typeof "hello" // "string"
typeof 42 // "number"
typeof true // "boolean"
typeof undefined // "undefined"
typeof null // "object" — this is a famous JS bug, null is NOT an object
typeof {} // "object"
typeof [] // "object" — arrays are objects
typeof function(){} // "function"Strings in Depth
const lang = "JavaScript";
// Length
lang.length // 10
// Access characters
lang[0] // "J"
lang.charAt(4) // "S"
// Common methods
lang.toUpperCase() // "JAVASCRIPT"
lang.toLowerCase() // "javascript"
lang.includes("Script") // true
lang.startsWith("Java") // true
lang.endsWith("Script") // true
lang.indexOf("a") // 1 (first occurrence)
lang.slice(4) // "Script"
lang.slice(0, 4) // "Java"
lang.replace("Java", "Type") // "TypeScript"
lang.split("") // ["J","a","v","a","S","c","r","i","p","t"]
const padded = " hello ";
padded.trim() // "hello"
padded.trimStart() // "hello "
// Template literals — backtick strings
const user = "Asma";
const score = 95;
const message = `${user} scored ${score}% — ${score >= 90 ? "excellent" : "good"}!`;
// "Asma scored 95% — excellent!"
// Multi-line template literal
const html = `
<div class="card">
<h2>${user}</h2>
<p>Score: ${score}</p>
</div>
`;Type Coercion and Equality
JavaScript will try to convert types automatically. This causes bugs if you don't understand it.
// == performs type coercion (loose equality)
0 == false // true — "0 == false" because false coerces to 0
"" == false // true
null == undefined // true
1 == "1" // true
// === checks type AND value (strict equality) — always use this
0 === false // false
"" === false // false
null === undefined // false
1 === "1" // falseAlways use === and !==. The == operator causes subtle bugs.
// Falsy values (evaluate to false in boolean context)
Boolean(false) // false
Boolean(0) // false
Boolean("") // false
Boolean(null) // false
Boolean(undefined) // false
Boolean(NaN) // false
// Everything else is truthy
Boolean("0") // true — "0" is truthy!
Boolean([]) // true — empty array is truthy!
Boolean({}) // true — empty object is truthy!Arithmetic and Comparison Operators
// Arithmetic
10 + 3 // 13
10 - 3 // 7
10 * 3 // 30
10 / 3 // 3.3333...
10 % 3 // 1 (remainder/modulo)
2 ** 10 // 1024 (exponentiation)
// Increment/decrement
let x = 5;
x++; // x becomes 6 (post-increment: returns 5, then increments)
++x; // x becomes 7 (pre-increment: increments first, returns 7)
x--; // x becomes 6
// String + number concatenation trap
"5" + 3 // "53" — number coerced to string
"5" - 3 // 2 — string coerced to number (subtraction only works on numbers)
+"5" // 5 — unary + converts string to number
// Logical operators
true && false // false (AND)
true || false // true (OR)
!true // false (NOT)
// Short-circuit evaluation
const user = null;
const name = user && user.name; // null — stops at user (falsy)
const fallback = user || "Guest"; // "Guest" — user is falsy, uses right side
// Nullish coalescing (??) — only falls back on null/undefined (not 0 or "")
const count = 0;
const display = count ?? "No items"; // 0 — count is not null/undefined
const display2 = count || "No items"; // "No items" — 0 is falsy!Functions
Function Declaration
function greet(name) {
return `Hello, ${name}!`;
}
greet("Asma"); // "Hello, Asma!"Function declarations are hoisted — you can call them before they appear in code.
Function Expression
const greet = function(name) {
return `Hello, ${name}!`;
};Arrow Functions
The modern, concise syntax. Use this most of the time.
// Full arrow function
const greet = (name) => {
return `Hello, ${name}!`;
};
// Implicit return (one expression, no braces needed)
const greet = (name) => `Hello, ${name}!`;
// Single parameter — parentheses optional
const double = x => x * 2;
// No parameters — empty parens required
const getRandom = () => Math.random();
// Returning an object — wrap in parens
const makeUser = (name, age) => ({ name, age });Parameters: Defaults, Rest, Spread
// Default parameters
function createUser(name, role = "viewer", active = true) {
return { name, role, active };
}
createUser("Asma"); // { name: "Asma", role: "viewer", active: true }
createUser("Ali", "admin"); // { name: "Ali", role: "admin", active: true }
// Rest parameters — collects remaining args into an array
function sum(...numbers) {
return numbers.reduce((total, n) => total + n, 0);
}
sum(1, 2, 3, 4, 5); // 15
// Spread — spreads an array into individual arguments
const nums = [1, 2, 3];
Math.max(...nums); // 3Scope
Scope determines where a variable is accessible.
// Global scope — accessible everywhere
const globalVar = "I'm everywhere";
function outer() {
// Function scope — accessible in this function and nested functions
const outerVar = "I'm in outer";
function inner() {
// Block scope — let/const are block-scoped
const innerVar = "I'm in inner";
console.log(globalVar); // ✓ accessible
console.log(outerVar); // ✓ accessible (closure)
console.log(innerVar); // ✓ accessible
}
inner();
console.log(innerVar); // ReferenceError — not accessible here
}
// Block scope with let/const
if (true) {
let blockVar = "only inside this if";
const alsoBlock = "same";
var varLeak = "I leak out!"; // var is NOT block-scoped
}
console.log(blockVar); // ReferenceError
console.log(varLeak); // "I leak out!" — var ignores block scopeClosures
A closure is a function that remembers the variables from its outer scope even after that outer function has returned.
function makeCounter(start = 0) {
let count = start; // this variable is "enclosed" in the returned function
return {
increment: () => ++count,
decrement: () => --count,
value: () => count,
reset: () => { count = start; }
};
}
const counter = makeCounter(10);
counter.increment(); // 11
counter.increment(); // 12
counter.decrement(); // 11
counter.value(); // 11
counter.reset();
counter.value(); // 10
// Each call to makeCounter gets its own independent closure
const counterA = makeCounter();
const counterB = makeCounter();
counterA.increment();
counterA.increment();
counterA.value(); // 2
counterB.value(); // 0 — independent!Closures are used everywhere in JavaScript: event handlers, callbacks, module patterns, memoization.
Higher-Order Functions
Functions that take other functions as arguments, or return functions.
// Function as argument
function applyTwice(fn, value) {
return fn(fn(value));
}
const double = x => x * 2;
applyTwice(double, 3); // 12
// Function returning a function
function multiplier(factor) {
return (number) => number * factor;
}
const triple = multiplier(3);
const tenTimes = multiplier(10);
triple(5); // 15
tenTimes(7); // 70Key Takeaways
- Use
constby default,letwhen you need to reassign, nevervar - Use
===always —==with type coercion causes subtle bugs - Arrow functions are the modern syntax — use them for most functions
- Closures let inner functions remember outer variables — essential pattern
nullis intentional absence,undefinedis "not yet set"- Template literals with backticks are cleaner than string concatenation