Variables: Storing Data
Variables are containers that store data values. Think of them as labeled boxes where you can put information and retrieve it later using the label.
JavaScript provides three ways to declare variables:
let - For Changeable Values
Use let when you need a variable whose value can change.
// Declare a variable
let age = 25;
console.log(age); // Output: 25
// Change the value
age = 26;
console.log(age); // Output: 26
// Declare without initial value
let score;
console.log(score); // Output: undefined
score = 100;
console.log(score); // Output: 100
const - For Fixed Values
Use const for values that should never change after assignment. This is the preferred choice when you know the value won't need to be reassigned.
// Constants cannot be reassigned
const PI = 3.14159;
const APP_NAME = "My Application";
const MAX_USERS = 100;
console.log(PI); // Output: 3.14159
// This will cause an error:
// PI = 3.14; // TypeError: Assignment to constant variable
// const must be initialized when declared
// const x; // SyntaxError: Missing initializer
const with Objects and Arrays
While you can't reassign a const, you CAN modify the contents of objects and arrays. The reference is constant, not the data inside.
// const with arrays - modifying content is allowed
const colors = ["red", "green"];
colors.push("blue"); // This works!
console.log(colors); // ["red", "green", "blue"]
// colors = ["yellow"]; // Error: can't reassign
// const with objects - modifying properties is allowed
const user = { name: "John" };
user.name = "Jane"; // This works!
user.age = 30; // This works too!
console.log(user); // { name: "Jane", age: 30 }
// user = { name: "Bob" }; // Error: can't reassign
var - The Legacy Way
var is the original way to declare variables in JavaScript. It's still supported but has quirks that can cause bugs.
// var works similarly to let for basic usage
var message = "Hello";
message = "Hi";
console.log(message); // "Hi"
// But var has different scoping rules (function-scoped)
// We'll cover this in detail in the Functions topic
Best Practice
Use const by default. Only use let when you know the value needs to change. Avoid var in modern JavaScript.
Variable Naming Rules
// Valid variable names
let firstName = "John"; // camelCase (recommended)
let last_name = "Doe"; // snake_case
let _private = "secret"; // can start with underscore
let $element = "jQuery"; // can start with $
let café = "coffee"; // Unicode letters allowed
let π = 3.14159; // Unicode symbols work too
// Invalid variable names
// let 123abc = "error"; // Cannot start with number
// let my-var = "error"; // Hyphens not allowed
// let let = "error"; // Cannot use reserved words
// Naming conventions
const MAX_SIZE = 100; // UPPER_SNAKE_CASE for constants
let userAge = 25; // camelCase for variables
let isActive = true; // prefix booleans with is/has/can
Naming Best Practices
Good variable names make your code self-documenting. Follow these conventions used by professional developers:
// 1. Variables and Functions: camelCase
let userName = "john_doe";
let totalPrice = 99.99;
function calculateTax(amount) { /* ... */ }
function getUserById(id) { /* ... */ }
// 2. Constants: UPPER_SNAKE_CASE
const API_BASE_URL = "https://api.example.com";
const MAX_RETRY_ATTEMPTS = 3;
const DEFAULT_TIMEOUT_MS = 5000;
// 3. Classes: PascalCase
class UserAccount { /* ... */ }
class ShoppingCart { /* ... */ }
class PaymentProcessor { /* ... */ }
// 4. Boolean variables: is/has/can/should prefix
let isLoggedIn = true;
let hasPermission = false;
let canEdit = true;
let shouldUpdate = false;
// 5. Arrays: plural nouns
let users = [];
let productItems = [];
let selectedColors = [];
// 6. Functions: verb + noun (action-oriented)
function fetchUserData() { /* ... */ }
function validateEmail(email) { /* ... */ }
function sendNotification(message) { /* ... */ }
// 7. Event handlers: handle + EventName
function handleClick(event) { /* ... */ }
function handleFormSubmit(event) { /* ... */ }
function handleMouseEnter(event) { /* ... */ }
// 8. Private members (convention): underscore prefix
class User {
_password = ""; // Indicates "private" (convention only)
#reallyPrivate; // Actually private (ES2022)
}
Reserved Words
JavaScript has reserved keywords that cannot be used as variable names. These words have special meaning in the language:
// ❌ These will cause errors if used as variable names:
// Control flow
// break, case, catch, continue, default, do, else, finally,
// for, if, return, switch, throw, try, while
// Declaration
// class, const, function, let, var
// Values
// false, null, true
// Operators
// delete, in, instanceof, new, typeof, void
// Other
// debugger, export, extends, import, super, this, with
// ❌ Also reserved for future use:
// await, enum, implements, interface, package, private,
// protected, public, static, yield
// ✅ These are NOT reserved and can be used (but avoid them):
let undefined = 5; // Works but terrible idea!
let NaN = "hello"; // Works but confusing!
let Infinity = 42; // Works but please don't!
Avoid Shadowing Built-ins
While you technically CAN use names like name, length, or status, they may conflict with browser properties. Be specific: use userName instead of name.
The Semicolon Debate
In JavaScript, semicolons are technically optional in many cases due to Automatic Semicolon Insertion (ASI). However, this feature can cause unexpected bugs.
How ASI Works
// JavaScript automatically inserts semicolons in these cases:
// 1. At the end of lines before a line terminator
let a = 1
let b = 2
// Becomes: let a = 1; let b = 2;
// 2. After return, throw, break, continue with line break
function getName() {
return
"John" // ASI inserts semicolon after return!
}
console.log(getName()); // undefined (not "John"!)
// 3. Before closing braces
function test() {
return true
} // ASI inserts semicolon before }
ASI Gotchas
// ❌ Problem 1: Return statement with line break
function getUser() {
return
{
name: "John",
age: 30
}
}
console.log(getUser()); // undefined!
// ✅ Solution: Keep opening brace on same line
function getUser() {
return {
name: "John",
age: 30
};
}
// ❌ Problem 2: IIFE after another statement
const message = "Hello"
(function() {
console.log("IIFE");
})()
// Error: "Hello" is not a function!
// ✅ Solution: Use semicolons
const message = "Hello";
(function() {
console.log("IIFE");
})();
// ❌ Problem 3: Array after statement
const a = 1
[1, 2, 3].forEach(n => console.log(n))
// Error: Cannot read property 'forEach' of undefined
// ✅ Solution: Prefix with semicolon when needed
const a = 1
;[1, 2, 3].forEach(n => console.log(n))
Team Decision
Whether to use semicolons is a team/project decision. Many projects use tools like Prettier or ESLint to enforce a consistent style automatically. The most important thing is consistency within your codebase.
Code Style Guides
Professional teams follow code style guides to ensure consistent, readable code. Here are the most popular ones:
Popular JavaScript Style Guides
- Airbnb JavaScript Style Guide - The most popular, very comprehensive
- Google JavaScript Style Guide - Used at Google
- JavaScript Standard Style - No semicolons, minimal config
- Prettier - Opinionated formatter (not a style guide, but enforces one)
Key Style Recommendations
// 1. Indentation: 2 spaces (common) or 4 spaces
function example() {
const name = "John"; // 2-space indent
}
// 2. Quotes: Be consistent (single or double)
const single = 'Hello'; // Airbnb prefers single
const double = "Hello"; // Google allows both
const template = `Hello ${name}`; // Template literals for interpolation
// 3. Trailing commas: Help with cleaner git diffs
const user = {
name: "John",
age: 30, // Trailing comma
};
const colors = [
"red",
"green",
"blue", // Trailing comma
];
// 4. Spacing around operators
const sum = a + b; // ✅ Spaces around operators
const sum = a+b; // ❌ Hard to read
// 5. Spacing in objects
const obj = { name: "John", age: 30 }; // ✅ Spaces after { and before }
const obj = {name:"John",age:30}; // ❌ Cramped
// 6. Function declarations
// Named function
function greet(name) {
return `Hello, ${name}!`;
}
// Arrow function for callbacks
const numbers = [1, 2, 3];
const doubled = numbers.map(n => n * 2);
// 7. Max line length: 80-120 characters
// Break long lines for readability
const longString = "This is a very long string that " +
"spans multiple lines for better readability.";
Data Types
JavaScript has eight data types. Seven are "primitive" (simple values) and one is "complex" (objects).
Primitive Types
1. String - Text Data
// Three ways to create strings
const single = 'Hello'; // Single quotes
const double = "World"; // Double quotes
const backtick = `Hello World`; // Template literals (backticks)
// String length
console.log(single.length); // 5
// Accessing characters
console.log(single[0]); // "H"
console.log(single[4]); // "o"
// Template literals - embed expressions
const name = "Alice";
const age = 25;
const greeting = `Hello, ${name}! You are ${age} years old.`;
console.log(greeting); // "Hello, Alice! You are 25 years old."
// Multi-line strings (only with backticks)
const multiLine = `
This is line 1
This is line 2
This is line 3
`;
// Escape characters
const escaped = "She said \"Hello!\""; // She said "Hello!"
const newLine = "Line 1\nLine 2"; // \n = new line
const tab = "Column1\tColumn2"; // \t = tab
2. Number - Numeric Data
// Integers and decimals are both "number" type
const integer = 42;
const decimal = 3.14;
const negative = -10;
// Scientific notation
const big = 1.5e6; // 1,500,000
const small = 1.5e-6; // 0.0000015
// Special numeric values
const infinity = Infinity;
const negInfinity = -Infinity;
const notANumber = NaN; // Result of invalid math
// Checking for special values
console.log(isNaN(NaN)); // true
console.log(isFinite(100)); // true
console.log(isFinite(Infinity)); // false
// Number methods
const num = 3.14159;
console.log(num.toFixed(2)); // "3.14" (string)
console.log(num.toPrecision(3)); // "3.14" (string)
// Parsing strings to numbers
console.log(parseInt("42")); // 42
console.log(parseFloat("3.14")); // 3.14
console.log(Number("123")); // 123
console.log(+"456"); // 456 (unary plus)
3. Boolean - True or False
// Boolean values
const isActive = true;
const isComplete = false;
// Comparisons return booleans
console.log(5 > 3); // true
console.log(5 < 3); // false
console.log(5 === 5); // true
// Truthy and Falsy values
// Falsy: false, 0, "", null, undefined, NaN
// Truthy: everything else
console.log(Boolean(0)); // false
console.log(Boolean("")); // false
console.log(Boolean(null)); // false
console.log(Boolean(undefined)); // false
console.log(Boolean(1)); // true
console.log(Boolean("hello")); // true
console.log(Boolean([])); // true (empty array is truthy!)
console.log(Boolean({})); // true (empty object is truthy!)
4. undefined - No Value Assigned
// Variable declared but not assigned
let x;
console.log(x); // undefined
console.log(typeof x); // "undefined"
// Function with no return value
function doNothing() {}
console.log(doNothing()); // undefined
// Accessing non-existent property
const obj = { name: "John" };
console.log(obj.age); // undefined
5. null - Intentional Empty Value
// null means "no value" intentionally
let selectedUser = null;
console.log(selectedUser); // null
// typeof null is "object" (historical bug)
console.log(typeof null); // "object"
// Checking for null
console.log(selectedUser === null); // true
// null vs undefined
let a; // undefined (not assigned)
let b = null; // null (intentionally empty)
console.log(a == b); // true (loose equality)
console.log(a === b); // false (strict equality)
6. Symbol - Unique Identifiers (ES6)
// Symbols are unique and immutable
const sym1 = Symbol("description");
const sym2 = Symbol("description");
console.log(sym1 === sym2); // false (always unique!)
// Useful for object property keys
const id = Symbol("id");
const user = {
name: "John",
[id]: 12345
};
console.log(user[id]); // 12345
7. BigInt - Large Integers (ES2020)
// Regular numbers have limits
const maxSafe = Number.MAX_SAFE_INTEGER;
console.log(maxSafe); // 9007199254740991
// BigInt for larger numbers (add 'n' suffix)
const bigNum = 9007199254740991n;
const anotherBig = BigInt("9999999999999999999999");
console.log(bigNum + 1n); // 9007199254740992n
// Cannot mix BigInt and regular numbers
// console.log(bigNum + 1); // TypeError!
The typeof Operator
// typeof returns a string describing the type
console.log(typeof "hello"); // "string"
console.log(typeof 42); // "number"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof Symbol()); // "symbol"
console.log(typeof 10n); // "bigint"
// Quirks
console.log(typeof null); // "object" (historical bug)
console.log(typeof []); // "object"
console.log(typeof {}); // "object"
console.log(typeof function(){}); // "function"
Operators
Arithmetic Operators
// Basic arithmetic
console.log(10 + 5); // 15 (addition)
console.log(10 - 5); // 5 (subtraction)
console.log(10 * 5); // 50 (multiplication)
console.log(10 / 5); // 2 (division)
console.log(10 % 3); // 1 (modulus/remainder)
console.log(2 ** 3); // 8 (exponentiation)
// Order of operations (PEMDAS)
console.log(2 + 3 * 4); // 14 (not 20)
console.log((2 + 3) * 4); // 20
// Increment and decrement
let count = 5;
count++; // count is now 6
count--; // count is now 5
// Pre vs post increment
let a = 5;
console.log(a++); // 5 (returns old value, then increments)
console.log(a); // 6
let b = 5;
console.log(++b); // 6 (increments first, then returns)
console.log(b); // 6
Comparison Operators
// Comparison operators return booleans
console.log(5 > 3); // true (greater than)
console.log(5 < 3); // false (less than)
console.log(5 >= 5); // true (greater than or equal)
console.log(5 <= 4); // false (less than or equal)
// Equality: == vs ===
console.log(5 == "5"); // true (loose: converts types)
console.log(5 === "5"); // false (strict: no conversion)
console.log(5 === 5); // true
// Inequality: != vs !==
console.log(5 != "5"); // false (loose)
console.log(5 !== "5"); // true (strict)
// String comparison (lexicographic)
console.log("apple" < "banana"); // true
console.log("a" < "b"); // true
console.log("2" > "10"); // true (string comparison!)
Best Practice
Always use === and !== (strict equality) to avoid unexpected type coercion bugs.
Logical Operators
// AND (&&) - both must be true
console.log(true && true); // true
console.log(true && false); // false
console.log(5 > 3 && 10 > 5); // true
// OR (||) - at least one must be true
console.log(true || false); // true
console.log(false || false); // false
console.log(5 > 10 || 10 > 5); // true
// NOT (!) - inverts the boolean
console.log(!true); // false
console.log(!false); // true
console.log(!0); // true (0 is falsy)
console.log(!""); // true (empty string is falsy)
// Short-circuit evaluation
const user = null;
const name = user && user.name; // undefined (doesn't error)
const defaultName = name || "Guest"; // "Guest"
// Nullish coalescing (??) - ES2020
const value = null ?? "default"; // "default"
const zero = 0 ?? "default"; // 0 (only null/undefined trigger default)
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
// Logical assignment (ES2021)
let a = null;
a ||= "default"; // a = a || "default" → "default"
let b = "hello";
b &&= "world"; // b = b && "world" → "world"
let c = null;
c ??= "fallback"; // c = c ?? "fallback" → "fallback"
Type Conversion
// To String
String(123); // "123"
(123).toString(); // "123"
123 + ""; // "123"
// To Number
Number("123"); // 123
Number("hello"); // NaN
Number(true); // 1
Number(false); // 0
parseInt("42px"); // 42
parseFloat("3.14"); // 3.14
+"123"; // 123 (unary plus)
// To Boolean
Boolean(1); // true
Boolean(0); // false
Boolean("hello"); // true
Boolean(""); // false
!!value; // Convert to boolean (double NOT)
// Automatic coercion (be careful!)
console.log("5" + 3); // "53" (string concatenation)
console.log("5" - 3); // 2 (subtraction converts to number)
console.log("5" * "2"); // 10 (multiplication converts)
console.log(true + true); // 2 (booleans become 1)
Type Coercion Deep Dive
Type coercion is JavaScript's automatic conversion of values from one type to another. Understanding it helps you avoid subtle bugs.
String Coercion
// The + operator with a string converts other operand to string
console.log("Hello " + 42); // "Hello 42"
console.log("Value: " + true); // "Value: true"
console.log("Items: " + null); // "Items: null"
console.log("Count: " + undefined); // "Count: undefined"
console.log("" + 123); // "123"
// Template literals also trigger string coercion
const num = 42;
console.log(`Number: ${num}`); // "Number: 42"
console.log(`Bool: ${true}`); // "Bool: true"
// Array to string
console.log([1, 2, 3] + ""); // "1,2,3"
console.log("Items: " + [1, 2]); // "Items: 1,2"
// Object to string (uses toString method)
console.log({} + ""); // "[object Object]"
console.log({name: "John"} + ""); // "[object Object]"
Number Coercion
// Math operators (except +) convert to numbers
console.log("10" - 5); // 5
console.log("10" * "2"); // 20
console.log("10" / 2); // 5
console.log("10" % 3); // 1
// Comparison operators
console.log("10" > 5); // true (string converted to number)
console.log("10" > "5"); // false! (string comparison, "1" < "5")
// Unary + operator converts to number
console.log(+"42"); // 42
console.log(+true); // 1
console.log(+false); // 0
console.log(+""); // 0
console.log(+null); // 0
console.log(+undefined); // NaN
console.log(+"hello"); // NaN
// Boolean to number
console.log(true * 10); // 10
console.log(false * 10); // 0
// null and undefined
console.log(null * 10); // 0 (null becomes 0)
console.log(undefined * 10); // NaN (undefined becomes NaN)
Boolean Coercion
// FALSY values (convert to false):
if (false) {} // false
if (0) {} // false
if (-0) {} // false
if (0n) {} // false (BigInt zero)
if ("") {} // false (empty string)
if (null) {} // false
if (undefined) {} // false
if (NaN) {} // false
// TRUTHY values (everything else converts to true):
if (true) {} // true
if (1) {} // true
if (-1) {} // true (any non-zero number)
if ("hello") {} // true (any non-empty string)
if ("0") {} // true! (string "0" is truthy)
if ("false") {} // true! (string "false" is truthy)
if ([]) {} // true! (empty array is truthy)
if ({}) {} // true! (empty object is truthy)
if (function(){}) {} // true (functions are truthy)
// Double NOT for explicit boolean conversion
console.log(!!"hello"); // true
console.log(!!""); // false
console.log(!!0); // false
console.log(!!1); // true
Equality Coercion Gotchas
// Surprising == comparisons (all true!)
console.log(0 == false); // true
console.log("" == false); // true
console.log(null == undefined); // true
console.log("0" == false); // true
console.log([] == false); // true
console.log([[]] == 0); // true
console.log([1] == 1); // true
// Even more confusing
console.log([] == ![]); // true! (wat?)
console.log([] == 0); // true
console.log([] == ""); // true
// === avoids all this confusion
console.log(0 === false); // false
console.log("" === false); // false
console.log(null === undefined); // false
console.log([] === false); // false
// When to use == (rarely)
// Only for null/undefined check:
if (value == null) {
// Catches both null and undefined
}
// Same as:
if (value === null || value === undefined) {
// More explicit but longer
}
The Golden Rule
Always use === and !== unless you have a specific reason to use ==. Type coercion in comparisons is one of the most common sources of bugs in JavaScript.
Comments
// This is a single-line comment
/*
This is a multi-line comment.
It can span multiple lines.
Useful for longer explanations.
*/
/**
* JSDoc comment - used for documentation
* @param {string} name - The user's name
* @returns {string} A greeting message
*/
function greet(name) {
return `Hello, ${name}!`;
}
// Comments are ignored by JavaScript
let x = 5; // This comment explains the variable
// Use comments to temporarily disable code
// console.log("This won't run");
Summary
In this chapter, you learned the fundamental building blocks of JavaScript:
- Variables: Use
constby default,letwhen values change, avoidvar - Naming Conventions: camelCase for variables, UPPER_SNAKE_CASE for constants, PascalCase for classes
- Reserved Words: Keywords like
let,const,class,functioncannot be variable names - Semicolons: Optional but recommended; be aware of ASI gotchas
- Style Guides: Follow team conventions (Airbnb, Google, StandardJS) for consistent code
- Data Types: String, Number, Boolean, undefined, null, Symbol, BigInt, and Object
- Operators: Arithmetic, comparison, logical, and assignment operators
- Type Coercion: JavaScript automatically converts types; use
===to avoid surprises - Comments: Document your code with single-line and multi-line comments
Next Steps
Now that you understand variables and data types, you're ready to learn how to control the flow of your programs with conditionals and loops!