var, let, and const
JavaScript has three ways to declare variables. Understanding the differences is crucial for writing predictable, bug-free code.
- var: Function-scoped, hoisted, can be redeclared (avoid using this)
- let: Block-scoped, not hoisted, cannot be redeclared
- const: Block-scoped, must be initialized, cannot be reassigned
// var - function scoped (avoid)
var name = "Alice";
var name = "Bob"; // No error, can redeclare
// let - block scoped
let age = 25;
age = 26; // OK, can reassign
// let age = 27; // Error: cannot redeclare
// const - must be initialized, cannot reassign
const PI = 3.14159;
// PI = 3; // Error: assignment to constant variable
// Const with objects/arrays - reference is const, not the value
const user = { name: "Alice", age: 25 };
user.age = 26; // OK, mutating the object
// user = {}; // Error: cannot reassign
// Block scoping example
{
let blockVar = "I'm block scoped";
const blockConst = "Me too";
}
// console.log(blockVar); // Error: blockVar is not defined
Primitive Data Types
JavaScript has 7 primitive types. Understanding each type's behavior prevents common bugs.
// String
const message = "Hello, World!";
const template = `My name is ${message}`;
// Number (integers and floats are the same type)
const integer = 42;
const float = 3.14;
const bigNum = 1_000_000; // Underscore separator (ES2021)
// BigInt - for very large integers
const bigInteger = 9007199254740991n;
// Boolean
const isActive = true;
const isLoggedIn = false;
// null - intentional absence of value
const emptyValue = null;
// undefined - variable declared but not assigned
let notAssigned;
console.log(notAssigned); // undefined
// Symbol - unique identifier
const id1 = Symbol("id");
const id2 = Symbol("id");
console.log(id1 === id2); // false, always unique
// typeof operator
console.log(typeof "hello"); // "string"
console.log(typeof 42); // "number"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object" (historical bug!)
console.log(typeof Symbol()); // "symbol"
Type Coercion & Comparison
JavaScript automatically converts types in certain situations (implicit coercion). This can lead to surprising results if you're not careful.
// Implicit type coercion
console.log(1 + "2"); // "12" (number coerced to string)
console.log("5" - 3); // 2 (string coerced to number)
console.log(true + 1); // 2 (true coerced to 1)
console.log(false + 1); // 1 (false coerced to 0)
// == vs === (always use ===)
console.log(0 == false); // true (loose equality)
console.log(0 === false); // false (strict equality)
console.log("" == false); // true (loose equality)
console.log("" === false);// false (strict equality)
console.log(null == undefined); // true
console.log(null === undefined); // false
// Explicit conversion
const numStr = "42";
const num = Number(numStr); // 42
const num2 = parseInt(numStr); // 42
const num3 = +numStr; // 42 (unary plus)
const boolNum = Boolean(0); // false
const boolStr = Boolean(""); // false
const boolNull = Boolean(null); // false
const boolTruthy = Boolean(1); // true
Always use === (strict equality) instead of == (loose equality) to avoid unexpected type coercion bugs.
Destructuring & Spread
Modern JavaScript provides elegant syntax for extracting values from arrays and objects, making your code more concise and readable.
// Object destructuring
const user = { name: "Alice", age: 25, city: "New York" };
const { name, age, city: location } = user;
console.log(name, age, location); // Alice 25 New York
// Array destructuring
const [first, second, ...rest] = [1, 2, 3, 4, 5];
console.log(first, second, rest); // 1 2 [3, 4, 5]
// Default values in destructuring
const { theme = "dark", language = "en" } = {};
console.log(theme, language); // dark en
// Nested destructuring
const config = {
server: { host: "localhost", port: 3000 },
database: { url: "postgres://..." }
};
const { server: { host, port } } = config;
console.log(host, port); // localhost 3000
// Spread operator
const defaults = { theme: "dark", lang: "en", fontSize: 14 };
const userPrefs = { lang: "hi", fontSize: 16 };
const merged = { ...defaults, ...userPrefs };
// { theme: "dark", lang: "hi", fontSize: 16 }
// Function parameter destructuring
function greet({ name, greeting = "Hello" }) {
return `${greeting}, ${name}!`;
}
console.log(greet({ name: "Farook" })); // Hello, Farook!