Skip to content

Variables and Data Types

Variables are used to store data values in memory, so that you can reuse them and work with them later in your program.

JavaScript gives you three ways to create (declare) a variable:

  • var (the old way, scoped to the whole function)
  • let (the modern way, scoped to a block)
  • const (scoped to a block, and its reference cannot be changed)

var

It is scoped to the whole function, you can declare it again with the same name, and it gets hoisted with a value of undefined.

let

It is scoped to a block, you cannot declare it again with the same name, and it is generally a safer choice than var.

const

It is scoped to a block, and once you set its value, you cannot reassign it later.

graph TD A[Variable Declaration] --> B[Memory Allocation] B --> C[Identifier: x] C --> D[Value: 10]

When you write:

let x = 10;
  • Some memory gets set aside for this variable.
  • A name (called an identifier), here x, is created for it.
  • The value 10 is stored inside that memory.
var x = 10;
var x = 20; // allowed
  • It is scoped to the whole function it is inside.
  • You are allowed to declare it again with the same name.
  • It gets hoisted (moved to the top) with the value undefined.

Scope simply means where in your code a variable can actually be used (accessed).

graph TD A[Global Scope] --> B[Function Scope] B --> C[Block Scope]
  • Global Scope -> this means the variable can be accessed from anywhere in your code.
  • Function Scope -> this means the variable can only be accessed inside the function it was declared in (this is how var behaves).
  • Block Scope -> this means the variable can only be accessed inside the {} it was declared in (this is how let and const behave).
{
let a = 10;
var b = 20;
}
console.log(b); // ✅ works
console.log(a); // ❌ error

Hoisting is a behavior in JavaScript where declarations are moved to the top of their scope before the code actually runs.

graph TD A[Code Written] --> B[Hoisted Phase] B --> C[Execution Phase]
console.log(x);
var x = 10;

Behind the scenes, this is actually treated like this:

var x;
console.log(x); // undefined
x = 10;
console.log(x); // ❌ ReferenceError
let x = 10;

This error happens because of something called the Temporal Dead Zone (TDZ). This basically means the variable exists, but you are not allowed to use it yet, until the line where it is actually declared.

JavaScript has two main categories of data types:

Primitive Types

These are values that cannot be changed (immutable) and are stored directly.

Reference Types

These are stored as a reference, which is basically just an address pointing to where the actual data lives in memory.

  1. Number This represents both whole numbers and decimal numbers. Example: 10, 3.14

  2. String This is simply a sequence of text characters. Example: "Hello"

  3. Boolean This can only be true or false.

  4. Undefined This means a variable was declared, but no value was ever given to it.

  5. Null This means the value is intentionally empty, on purpose.

  6. Symbol This creates a unique identifier that no other value can match.

  7. BigInt This is used for very large numbers that go beyond what the normal Number type can safely hold.

  • Objects
  • Arrays
  • Functions
graph LR A[Primitive] --> B[Value Stored Directly] C[Reference] --> D[Stored in Heap] D --> E[Reference Address]
let a = 10;
let b = a;
b = 20;
console.log(a); // 10
let obj1 = { name: "Sahil" };
let obj2 = obj1;
obj2.name = "Kumar";
console.log(obj1.name); // Kumar

In the first example, a and b are separate copies, so changing b does not affect a. But in the second example, obj1 and obj2 both point to the same object in memory, so changing one also changes the other.

This is used to check the type of a variable.

typeof 10; // "number"
typeof "hello"; // "string"
typeof true; // "boolean"
typeof undefined; // "undefined"
typeof null; // "object" (bug)

Note that typeof null returns "object", even though null is not really an object. This is a well-known bug that has existed in JavaScript for a long time.

Use let instead of var

This helps you avoid bugs that come from how var is scoped to the whole function.

Use const by default

Only switch to let when you actually need to change the value later.

Avoid global variables

This keeps your code clean and easier to predict.

Understand scope deeply

This helps you avoid confusing logical errors later on.