Understanding Variables and Data Types in JavaScript

JavaScript Variables: Your First Step into Coding
If you're just starting out with JavaScript, variables are one of the very first things you'll learn — and for good reason. They're the foundation of almost everything you'll ever build.
Let's break it all down in the simplest way possible.
What is a Variable? (The Box Analogy)
Imagine you have a labeled box sitting on your desk.
You write a name on the outside of the box (like "myName")
You put something inside it (like the text "Arjun")
Whenever you need that information, you just look at the box label
That's exactly what a variable is in programming — a named container that stores a piece of information.
// Declaring a variable and storing a value in it
let myName = "Arjun";
// Reading the variable — JavaScript looks up the box and gives you what's inside
console.log(myName); // "Arjun"
// You can use a variable wherever you'd use the value directly
console.log("Hello, " + myName + "!"); // "Hello, Arjun!"
Here, myName is the box label, and "Arjun" is what's inside it.
Primitive Data Types
Before we go further, let's look at the kinds of things you can store in a variable. JavaScript has five primitive data types you'll use constantly.
1. String — Text
Any text wrapped in quotes. You can use single quotes, double quotes, or backticks.
let firstName = "Arjun";
let lastName = 'Sharma';
let city = `Mumbai`;
// Backticks let you embed variables directly inside a string — called a template literal
let fullName = `\({firstName} \){lastName}`;
console.log(fullName); // "Arjun Sharma"
// You can also concatenate strings with the + operator
let greeting = "Hello, " + firstName + "!";
console.log(greeting); // "Hello, Arjun!"
// Checking the type of a value
console.log(typeof firstName); // "string"
// A string that looks like a number is still a string
let zipCode = "400001";
console.log(typeof zipCode); // "string"
2. Number — Numeric values
Any number — integers, decimals, negatives. JavaScript doesn't separate them into different types.
let age = 21;
let price = 9.99;
let temperature = -5;
let bigNumber = 1_000_000; // Underscores are allowed for readability
// Basic math with number variables
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 after dividing)
console.log(a ** b); // 1000 (10 to the power of 3)
// Checking the type
console.log(typeof age); // "number"
console.log(typeof price); // "number"
// A special number value — result of invalid math
let invalid = 10 / "hello";
console.log(invalid); // NaN (Not a Number)
console.log(typeof invalid); // "number" — NaN is still typed as number, a known quirk
3. Boolean — True or False
Only two possible values. Think of it as a yes/no switch.
let isStudent = true;
let isLoggedIn = false;
let hasSubscription = false;
console.log(typeof isStudent); // "boolean"
// Booleans are often the result of comparisons
let userAge = 20;
let canVote = userAge >= 18;
console.log(canVote); // true
let isTeenager = userAge >= 13 && userAge <= 19;
console.log(isTeenager); // true
// Using booleans to make decisions
if (isLoggedIn) {
console.log("Welcome back!");
} else {
console.log("Please log in.");
}
// Output: "Please log in."
4. Null — Intentionally empty
When you deliberately want a variable to hold no value. It's a way of saying "this box exists, but I'm leaving it empty on purpose."
let selectedColor = null;
let activeUser = null;
let cartItem = null;
console.log(selectedColor); // null
console.log(typeof selectedColor); // "object" — this is a known quirk in JavaScript
// A common pattern: start as null, then assign a real value later
let loggedInUser = null;
let loginSuccessful = true;
if (loginSuccessful) {
loggedInUser = "Arjun";
}
console.log(loggedInUser); // "Arjun"
// Checking if something is null
if (cartItem === null) {
console.log("Your cart is empty.");
}
// Output: "Your cart is empty."
5. Undefined — Not yet given a value
When a variable is declared but you haven't put anything in it yet, JavaScript automatically sets it to undefined.
let score;
let address;
console.log(score); // undefined
console.log(typeof score); // "undefined"
// The difference between null and undefined
let a = null; // You intentionally left it empty
let b; // You just haven't set it yet
console.log(a === b); // false — not strictly equal
console.log(a == b); // true — loosely equal (both represent "empty")
console.log(typeof a); // "object"
console.log(typeof b); // "undefined"
Declaring Variables: var, let, and const
JavaScript gives you three keywords to declare a variable. Each behaves differently.
var — The old way
var userName = "Arjun";
var userAge = 21;
console.log(userName); // "Arjun"
// var can be redeclared without any error — which can silently cause bugs
var userName = "Ravi"; // No error — overwrites the previous value
console.log(userName); // "Ravi"
// var can also be reassigned freely
var userAge = 25;
console.log(userAge); // 25
// var is function-scoped, not block-scoped
// This means it leaks out of if-blocks and for-loops
if (true) {
var leakyVariable = "I escaped the block!";
}
console.log(leakyVariable); // "I escaped the block!" — often an unintended bug
Most modern code avoids var because of this leaky scoping and silent redeclaration behavior.
let — When the value can change
let score = 0;
console.log(score); // 0
// Reassigning works fine
score = 10;
console.log(score); // 10
// You can update based on current value
score = score + 5;
console.log(score); // 15
// Shorthand operators for the same thing
score += 5; // score = score + 5
score -= 2; // score = score - 2
score *= 2; // score = score * 2
score++; // score = score + 1
score--; // score = score - 1
console.log(score); // 37
// let cannot be redeclared in the same scope
let username = "Arjun";
// let username = "Ravi"; // SyntaxError: Identifier 'username' has already been declared
// A realistic use case — tracking a running total
let totalPrice = 0;
let item1 = 49.99;
let item2 = 19.99;
let item3 = 9.99;
totalPrice += item1;
totalPrice += item2;
totalPrice += item3;
console.log("Total:", totalPrice); // "Total: 79.97"
const — When the value should stay the same
const birthYear = 2003;
const PI = 3.14159;
const MAX_ATTEMPTS = 3;
const APP_NAME = "MyApp";
console.log(birthYear); // 2003
console.log(PI); // 3.14159
// Trying to reassign a const throws a TypeError
// birthYear = 2005; // TypeError: Assignment to constant variable.
// Trying to redeclare also throws an error
// const PI = 3; // SyntaxError: Identifier 'PI' has already been declared
// A realistic use case — API config that should never change at runtime
const BASE_URL = "https://api.example.com";
const API_VERSION = "v1";
const endpoint = `\({BASE_URL}/\){API_VERSION}/users`;
console.log(endpoint); // "https://api.example.com/v1/users"
// Another realistic use case — calculating with a fixed constant
const TAX_RATE = 0.18;
let productPrice = 500;
let tax = productPrice * TAX_RATE;
let finalPrice = productPrice + tax;
console.log("Product:", productPrice); // 500
console.log("Tax:", tax); // 90
console.log("Final:", finalPrice); // 590
Rule of thumb: Always start with
const. If you later realize the value needs to change, switch tolet. Avoidvar.
Comparison Table: var vs let vs const
| Feature | var |
let |
const |
|---|---|---|---|
| Can be reassigned? | Yes | Yes | No |
| Block scoped? | No | Yes | Yes |
| Can be redeclared? | Yes | No | No |
| Modern best practice? | Avoid | Use | Use |
What is Scope? (The Room Analogy)
Scope means: "Where in your code can this variable be seen and used?"
Think of your code like a house. The global scope is the living room — everyone in the house can access it. A block scope (anything inside { }) is like a private bedroom — only code inside that block can see what's there.
Global Scope
// Declared outside any block — globally available
let appName = "MyApp";
let version = 1;
if (true) {
// Can access global variables from inside a block
console.log(appName); // "MyApp"
console.log(version); // 1
}
console.log(appName); // "MyApp" — still accessible here too
console.log(version); // 1
Block Scope with let and const
let outerMessage = "I am outside";
if (true) {
let innerMessage = "I am inside the block";
const blockId = 42;
console.log(outerMessage); // "I am outside" — outer variables visible inside
console.log(innerMessage); // "I am inside the block"
console.log(blockId); // 42
}
console.log(outerMessage); // "I am outside" — still works fine
// console.log(innerMessage); // ReferenceError: innerMessage is not defined
// console.log(blockId); // ReferenceError: blockId is not defined
Why var Causes Problems
// var leaks out of blocks
if (true) {
var leaky = "I can be seen outside!";
let safe = "I stay inside.";
}
console.log(leaky); // "I can be seen outside!" — var ignores the block boundary
// console.log(safe); // ReferenceError — let respects the block boundary
// A common bug — var leaking out of a for loop
for (var i = 0; i < 3; i++) {
// loop body
}
console.log(i); // 3 — i escaped the loop, which is almost never what you want
for (let j = 0; j < 3; j++) {
// loop body
}
// console.log(j); // ReferenceError — j stays inside the loop where it belongs
Nested Scope
let level = "global";
if (true) {
let level = "block"; // A new, separate variable — doesn't affect the global one
console.log(level); // "block"
if (true) {
let level = "nested block"; // Yet another separate variable
console.log(level); // "nested block"
}
console.log(level); // "block" — back to the block-level variable
}
console.log(level); // "global" — the original, untouched
Scope Visualization
┌──────────────────────────────────────────────┐
│ GLOBAL SCOPE │
│ │
│ let appName = "MyApp"; │
│ const version = 1; │
│ │
│ ┌──────────────────────────────────────┐ │
│ │ BLOCK SCOPE (if / for) │ │
│ │ │ │
│ │ let innerMessage = "only here"; │ │
│ │ const blockId = 42; │ │
│ │ │ │
│ │ can access: appName, version │ │
│ │ can access: innerMessage, blockId │ │
│ └──────────────────────────────────────┘ │
│ │
│ can access: appName, version │
│ cannot access: innerMessage, blockId │
└──────────────────────────────────────────────┘
Assignment: Try It Yourself
Here's your hands-on challenge. Type this out in your browser console or any JavaScript playground like playcode.io.
Step 1: Declare your variables
const name = "Arjun"; // String — won't change
let age = 21; // Number — might change
let isStudent = true; // Boolean — might change
Step 2: Print them to the console
console.log("Name:", name);
console.log("Age:", age);
console.log("Is Student:", isStudent);
// Using a template literal to print all at once
console.log(`\({name} is \){age} years old. Student: ${isStudent}`);
Output:
Name: Arjun
Age: 21
Is Student: true
Arjun is 21 years old. Student: true
Step 3: Try changing values
// Updating a let variable — works perfectly
age = 22;
console.log("Updated Age:", age); // 22
isStudent = false;
console.log("Still a student?", isStudent); // false
// Trying to change a const — throws a TypeError
// name = "Ravi"; // TypeError: Assignment to constant variable.
Step 4: Experiment with scope
const appTitle = "Student Tracker";
if (isStudent) {
let status = "enrolled";
console.log(`\({appTitle}: User is \){status}`);
} else {
let status = "not enrolled";
console.log(`\({appTitle}: User is \){status}`);
}
// Try uncommenting this — it will throw a ReferenceError
// console.log(status); // ReferenceError: status is not defined
What to observe: let updates smoothly. const throws an error the moment you try to reassign it. Variables declared with let or const inside a block are invisible outside of it.
Quick Recap
A variable is a named container for storing data
Use
constwhen the value won't changeUse
letwhen the value might change laterAvoid
varin modern JavaScript — it has scoping behavior that causes bugsScope controls where a variable can be accessed
letandconstare block-scoped;varis not



