Description and basic syntax

Description and Basic Syntax

JavaScript is the programming language of the web, transforming static HTML documents into dynamic, interactive applications. Along with HTML (structure) and CSS (presentation), JavaScript provides the behavior layer that brings web pages to life.

Core Characteristics:

  • High-level Language: Abstracts away memory management and low-level details

  • Just-in-Time Compiled: Modern engines compile JavaScript for performance

  • Dynamic Typing: Variable types are determined at runtime

  • Single-threaded: Executes one operation at a time

  • Non-blocking & Asynchronous: Can handle multiple operations through callbacks and promises

  • Multi-paradigm: Supports procedural, object-oriented, and functional programming styles

JavaScript in 100 Seconds

The evolution of JavaScript

JavaScript was created in 1995 by Brendan Eich at Netscape to add interactivity to web pages. Since then, it has evolved dramatically:

  • ECMAScript: The standardized specification that JavaScript implements

  • ES6 (2015): Revolutionary update that modernized the language (covered in Advanced JavaScript)

  • Modern JavaScript: Continuous yearly updates adding powerful features

Today, JavaScript runs not just in browsers but also on servers (Node.js), mobile devices, desktop applications, and even embedded systems.

Adding JavaScript to a web page

JavaScript can be integrated into HTML in three ways, each with specific use cases:

1. Inline JavaScript (avoid in production)

<!-- Inline event handler -->
<button type="button" onclick="document.getElementById('demo').innerHTML = Date()">
  Click me to show the date
</button>

<p id="demo"></p>

2. Internal JavaScript (script tags)

<!DOCTYPE html>
<html>
<head>
  <title>Internal JavaScript Example</title>
</head>
<body>
  <h1>Welcome!</h1>
  <p id="demo"></p>

  <!-- JavaScript before closing body tag for better performance -->
  <script>
    // This code runs when the browser parses this script tag
    document.getElementById("demo").innerHTML = "Hello JavaScript!";
    
    console.log("Page loaded successfully");
  </script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
  <title>External JavaScript Example</title>
  <meta charset="UTF-8">
</head>
<body>
  <h1>Welcome!</h1>
  <p id="demo"></p>

  <!-- Load external JavaScript file -->
  <script src="js/script.js"></script>
  
  <!-- Modern approach: defer attribute -->
  <script src="js/script.js" defer></script>
  
  <!-- For non-critical scripts: async attribute -->
  <script src="js/analytics.js" async></script>
</body>
</html>
// js/script.js
document.getElementById("demo").innerHTML = "Hello from external file!";

console.log("External JavaScript loaded");

// You can organize multiple functions in external files
function greetUser(name) {
  return `Hello, ${name}!`;
}

JavaScript syntax fundamentals

Statements and Comments

JavaScript code consists of statements that perform actions. Each statement typically ends with a semicolon (optional but recommended).

// Single-line comment explaining the next line
var myNumber = 3;  // Variable declaration and assignment

/* 
  Multi-line comment
  for longer explanations
  or temporarily disabling code
*/
counter = counter + 1;  // Increment operation

myFunction();  // Function call

// Function declaration
function myFunction() {
  console.log('Hello World!');
  return true;  // Optional return value
}

// Semicolons are technically optional due to Automatic Semicolon Insertion (ASI)
// but using them explicitly prevents edge-case bugs
let x = 5
let y = 10  // This works, but explicit semicolons are safer

Case sensitivity and naming conventions

// JavaScript is case-sensitive
let myVariable = 10;
let myvariable = 20;  // Different variable!
let MYVARIABLE = 30;  // Also different!

// Naming conventions (camelCase for variables and functions)
let firstName = "John";
let lastName = "Doe";
let userAge = 25;

function calculateTotal() { }
function getUserName() { }

// Constants use UPPER_SNAKE_CASE
const MAX_USERS = 100;
const API_URL = "https://api.example.com";

// Classes use PascalCase (covered later)
class UserAccount { }
class ShoppingCart { }

// Private variables often start with underscore (convention, not enforced)
let _privateVariable = "internal use";

JavaScript uses camelCase for variable and function names (myVariable, getUserData), UPPER_SNAKE_CASE for constants (MAX_VALUE), and PascalCase for class names (UserAccount). Following these conventions makes code readable and helps other developers understand your intent. The language is case-sensitive, so variable, Variable, and VARIABLE are three distinct identifiers.

Variables and data types

Variables are containers that store data values. JavaScript has three ways to declare variables, each with different behaviors:

Variable Declaration Keywords

// var (old way, function-scoped, avoid in modern code)
var oldStyle = "function-scoped";
var oldStyle = "can be redeclared";  // No error, but problematic

// let (modern, block-scoped, can be reassigned)
let modernStyle = "block-scoped";
modernStyle = "value can change";  // Reassignment allowed
// let modernStyle = "error";  // SyntaxError: Cannot redeclare

// const (modern, block-scoped, cannot be reassigned)
const constant = "cannot change";
// constant = "new value";  // TypeError: Assignment to constant variable

// But object/array contents CAN be modified with const
const user = { name: "John" };
user.name = "Jane";  // This works! Only the reference is constant
user.age = 30;       // Can add properties

const numbers = [1, 2, 3];
numbers.push(4);     // This works! Only the reference is constant
// numbers = [5, 6];  // TypeError: Cannot reassign

JavaScript Data Types

JavaScript has eight data types: seven primitive types and objects.

JavaScript Data Types

Primitive Data Types

// 1. String - Text data enclosed in quotes
let singleQuotes = 'Hello';
let doubleQuotes = "World";
let templateLiteral = `Hello ${singleQuotes}`;  // Template literals with interpolation
let multiline = `This string
spans multiple
lines`;

// 2. Number - Both integers and decimals
let integer = 42;
let decimal = 3.14159;
let negative = -10;
let scientific = 2.5e6;  // 2,500,000
let infinity = Infinity;
let notANumber = NaN;  // Result of invalid math operations

// 3. Boolean - true or false
let isActive = true;
let isCompleted = false;
let comparison = 5 > 3;  // true

// 4. Undefined - Variable declared but not assigned
let notYetAssigned;  // undefined
let explicitUndefined = undefined;

// 5. Null - Intentional absence of value
let emptyValue = null;  // Explicitly "no value"

// 6. Symbol - Unique identifier (ES6+)
let uniqueId = Symbol('id');
let anotherId = Symbol('id');
// uniqueId === anotherId;  // false, each symbol is unique

// 7. BigInt - Large integers beyond Number.MAX_SAFE_INTEGER (ES2020+)
let bigNumber = 1234567890123456789012345678901234567890n;
let anotherBig = BigInt("9007199254740991");

Object data type

// Object - Collection of key-value pairs
const person = {
  firstName: "John",
  lastName: "Doe",
  age: 30,
  isEmployed: true,
  address: {
    city: "New York",
    country: "USA"
  },
  hobbies: ["reading", "coding", "gaming"]
};

// Accessing object properties
console.log(person.firstName);        // "John" (dot notation)
console.log(person["lastName"]);      // "Doe" (bracket notation)
console.log(person.address.city);     // "New York" (nested access)

// Arrays - Special type of object for ordered lists
const numbers = [1, 2, 3, 4, 5];
const mixed = [1, "two", true, null, {key: "value"}];

// Accessing array elements (zero-indexed)
console.log(numbers[0]);    // 1
console.log(numbers[4]);    // 5
console.log(numbers.length); // 5

// Arrays are objects
console.log(typeof numbers);  // "object"
console.log(Array.isArray(numbers));  // true

Objects store collections of data as key-value pairs. Properties can be accessed using dot notation (person.firstName) or bracket notation (person["firstName"]). Bracket notation is required when property names have spaces, special characters, or are stored in variables. Arrays are special objects optimized for ordered data, accessed by numeric indices starting at 0. Arrays can contain mixed types, and their length property always reflects the number of elements.

Type checking and conversion

// Checking types with typeof
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 {});           // "object"
console.log(typeof []);           // "object" (arrays are objects)
console.log(typeof function(){}); // "function"

// Type conversion (coercion)
// Explicit conversion
let numString = "123";
let num = Number(numString);       // 123
let str = String(456);             // "456"
let bool = Boolean(1);             // true

// Implicit conversion (coercion)
let result = "5" + 2;    // "52" (number coerced to string)
let math = "5" - 2;      // 3 (string coerced to number)
let weird = "5" * "2";   // 10 (both coerced to numbers)

// Truthy and falsy values
// Falsy: false, 0, "", null, undefined, NaN
// Everything else is truthy
if ("hello") {  // truthy
  console.log("Strings are truthy");
}

if (0) {  // falsy, won't execute
  console.log("Never runs");
}

Functions

Functions are reusable blocks of code that perform specific tasks. They are fundamental building blocks in JavaScript and are themselves values that can be passed around.

Function declaration

// Basic function declaration
function greet(name) {
  console.log("Hello, " + name + "!");
}

greet("Alice");  // "Hello, Alice!"

// Function with return value
function add(a, b) {
  return a + b;
}

let sum = add(5, 3);  // 8

// Function with multiple parameters and default values
function introduce(name, age = 18, city = "Unknown") {
  return `${name} is ${age} years old and lives in ${city}`;
}

console.log(introduce("John"));           // "John is 18 years old and lives in Unknown"
console.log(introduce("Jane", 25));       // "Jane is 25 years old and lives in Unknown"
console.log(introduce("Bob", 30, "NYC")); // "Bob is 30 years old and lives in NYC"

// Functions without return statement return undefined
function noReturn() {
  console.log("This function returns nothing explicit");
}

let result = noReturn();  // undefined

Function Scope

// Global scope
const globalVar = "I'm global";

function demonstrateScope() {
  // Function scope
  const localVar = "I'm local";
  
  console.log(globalVar);  // Accessible: "I'm global"
  console.log(localVar);   // Accessible: "I'm local"
  
  if (true) {
    // Block scope (let/const)
    const blockVar = "I'm block-scoped";
    var functionVar = "I'm function-scoped";
    
    console.log(blockVar);     // Accessible: "I'm block-scoped"
    console.log(functionVar);  // Accessible: "I'm function-scoped"
  }
  
  // console.log(blockVar);  // Error: blockVar is not defined
  console.log(functionVar);  // Accessible: "I'm function-scoped"
}

demonstrateScope();

// console.log(localVar);  // Error: localVar is not defined

// Function parameters are locally scoped
function calculate(x, y) {
  const result = x + y;  // result is local to this function
  return result;
}

// console.log(x);      // Error: x is not defined
// console.log(result); // Error: result is not defined

JavaScript uses lexical (static) scoping where variables are accessible based on where they're defined in the code. Variables declared outside functions are global and accessible everywhere. Variables declared inside functions are local and only accessible within that function. Modern let and const use block scope (within {}), while old var uses function scope, which is another reason to avoid var. Function parameters and locally declared variables are not accessible outside the function, preventing naming conflicts and improving code organization.

Function expressions and arrow Functions

// Function expression (function as a value)
const multiply = function(a, b) {
  return a * b;
};

console.log(multiply(4, 5));  // 20

// Arrow function (ES6+ - concise syntax)
const subtract = (a, b) => {
  return a - b;
};

// Arrow function with implicit return (one expression)
const divide = (a, b) => a / b;

// Arrow function with single parameter (parentheses optional)
const square = x => x * x;

// Arrow function with no parameters
const getRandom = () => Math.random();

console.log(divide(10, 2));   // 5
console.log(square(5));       // 25
console.log(getRandom());     // Random number between 0 and 1

Operators

JavaScript provides various operators for performing operations on values and variables.

JavaScript Operators

Arithmetic operators

// Basic math operations
let a = 10;
let b = 3;

console.log(a + b);   // 13 - Addition
console.log(a - b);   // 7  - Subtraction
console.log(a * b);   // 30 - Multiplication
console.log(a / b);   // 3.333... - Division
console.log(a % b);   // 1  - Modulus (remainder)
console.log(a ** b);  // 1000 - Exponentiation (ES7+)

// Increment and decrement
let counter = 5;
counter++;     // Post-increment: 6
++counter;     // Pre-increment: 7
counter--;     // Post-decrement: 6
--counter;     // Pre-decrement: 5

// Difference between pre and post increment
let x = 5;
let y = x++;   // y = 5, x = 6 (assign then increment)
let z = ++x;   // z = 7, x = 7 (increment then assign)

Arithmetic operators perform mathematical calculations. The modulus operator (%) returns the remainder after division, useful for checking even/odd numbers or cycling through values. Exponentiation (**) raises a number to a power. Increment (++) and decrement (--) operators have two forms: postfix (x++) assigns the current value then increments, while prefix (++x) increments then assigns the new value.

Assignment operators

// Basic assignment
let num = 10;

// Compound assignment operators (shorthand)
num += 5;   // num = num + 5;  Result: 15
num -= 3;   // num = num - 3;  Result: 12
num *= 2;   // num = num * 2;  Result: 24
num /= 4;   // num = num / 4;  Result: 6
num %= 4;   // num = num % 4;  Result: 2
num **= 3;  // num = num ** 3; Result: 8

// String concatenation with +=
let message = "Hello";
message += " World";  // "Hello World"
message += "!";       // "Hello World!"

Compound assignment operators combine an operation with assignment, providing shorter syntax. x += 5 is equivalent to x = x + 5. These operators work with all arithmetic operations and are more concise and often more performant than writing out the full expression. The += operator is particularly useful for string concatenation and building messages incrementally.

Comparison operators

// Equality operators
console.log(5 == "5");    // true  - Loose equality (type coercion)
console.log(5 === "5");   // false - Strict equality (no coercion)
console.log(5 != "5");    // false - Loose inequality
console.log(5 !== "5");   // true  - Strict inequality

// Relational operators
console.log(10 > 5);      // true
console.log(10 < 5);      // false
console.log(10 >= 10);    // true
console.log(10 <= 5);     // false

// Comparing strings (lexicographic order)
console.log("apple" < "banana");  // true
console.log("Z" < "a");           // true (uppercase comes before lowercase in Unicode)

// Type coercion pitfalls
console.log(0 == false);    // true  (both coerced to falsy)
console.log(0 === false);   // false (different types)
console.log("" == false);   // true  (both coerced to falsy)
console.log("" === false);  // false (different types)
console.log(null == undefined);   // true  (special case)
console.log(null === undefined);  // false (different types)

Logical operators

// AND (&&) - Both must be true
console.log(true && true);    // true
console.log(true && false);   // false
console.log(false && true);   // false

// OR (||) - At least one must be true
console.log(true || false);   // true
console.log(false || false);  // false
console.log(true || true);    // true

// NOT (!) - Inverts boolean
console.log(!true);           // false
console.log(!false);          // true
console.log(!!0);             // false (double negation converts to boolean)

// Short-circuit evaluation
const user = null;
const defaultName = user || "Guest";  // "Guest" (user is falsy)

const isLoggedIn = true;
isLoggedIn && console.log("Welcome!");  // Executes (first is truthy)

// Combining logical operators
const age = 25;
const hasLicense = true;
const canDrive = age >= 18 && hasLicense;  // true

// Logical assignment operators (ES2021+)
let value = null;
value ||= 10;  // value = value || 10; (assigns if falsy)
console.log(value);  // 10

let count = 5;
count &&= 20;  // count = count && 20; (assigns if truthy)
console.log(count);  // 20

Logical operators work with boolean values and use short-circuit evaluation. The AND operator (&&) returns the first falsy value or the last value if all are truthy.

The OR operator (||) returns the first truthy value or the last value if all are falsy. This behavior enables common patterns like default values (value || defaultValue) and conditional execution (condition && executeThis()).

The NOT operator (!) converts values to boolean and inverts them—double NOT (!!) is a trick to convert any value to its boolean equivalent.

Ternary (Conditional) Operator

// Syntax: condition ? expressionIfTrue : expressionIfFalse

// Simple example
const age = 20;
const status = age >= 18 ? "Adult" : "Minor";
console.log(status);  // "Adult"

// Function with ternary
function checkAge(person) {
  return person.age < 18 ? "Too young" : "Allowed";
}

// Ternary in template literals
const user = { name: "Alice", isAdmin: true };
console.log(`Welcome ${user.isAdmin ? "Admin " : ""}${user.name}`);
// "Welcome Admin Alice"

// Nested ternary (use sparingly, can reduce readability)
const score = 85;
const grade = score >= 90 ? "A" : 
              score >= 80 ? "B" : 
              score >= 70 ? "C" : "F";
console.log(grade);  // "B"

// Better approach for complex conditions: use if/else

Conditional statements

Conditional statements control program flow based on boolean conditions.

If / Else If / Else

// Basic if statement
const temperature = 25;

if (temperature > 30) {
  console.log("It's hot!");
}

// If-else
const age = 16;

if (age >= 18) {
  console.log("You can vote");
} else {
  console.log("Too young to vote");
}

// If-else if-else (multiple conditions)
const score = 85;

if (score >= 90) {
  console.log("Grade: A");
} else if (score >= 80) {
  console.log("Grade: B");
} else if (score >= 70) {
  console.log("Grade: C");
} else if (score >= 60) {
  console.log("Grade: D");
} else {
  console.log("Grade: F");
}

// Multiple conditions with logical operators
const user = {
  age: 25,
  hasLicense: true,
  hasInsurance: true
};

if (user.age >= 18 && user.hasLicense && user.hasInsurance) {
  console.log("You can rent a car");
} else {
  console.log("Requirements not met");
}

// Nested conditionals
const isWeekend = true;
const weather = "sunny";

if (isWeekend) {
  if (weather === "sunny") {
    console.log("Perfect day for outdoor activities!");
  } else {
    console.log("Stay indoors and relax");
  }
} else {
  console.log("It's a work day");
}

Conditional statements execute different code blocks based on boolean conditions. The if statement runs code only if its condition is true. The else clause handles the false case. The else if allows multiple conditions to be checked in sequence—only the first true condition executes. Conditions can use logical operators to combine multiple checks. Avoid deeply nested conditionals when possible by using early returns or restructuring logic for better readability.

Switch statements

// Switch for multiple discrete values
const day = "Monday";

switch (day) {
  case "Monday":
    console.log("Start of the work week");
    break;
  case "Tuesday":
  case "Wednesday":
  case "Thursday":
    console.log("Midweek");
    break;
  case "Friday":
    console.log("TGIF!");
    break;
  case "Saturday":
  case "Sunday":
    console.log("Weekend!");
    break;
  default:
    console.log("Invalid day");
}

// Switch with fall-through (intentional, use cautiously)
const month = 2;
let days;

switch (month) {
  case 1: case 3: case 5: case 7: case 8: case 10: case 12:
    days = 31;
    break;
  case 4: case 6: case 9: case 11:
    days = 30;
    break;
  case 2:
    days = 28;  // Simplified, not accounting for leap years
    break;
  default:
    days = 0;
}

console.log(`This month has ${days} days`);

Switch statements provide cleaner syntax than multiple if-else statements when checking a single value against many discrete options. Each case clause checks for equality (strict ===). The break statement prevents fall-through to subsequent cases—without it, execution continues to the next case. Fall-through can be intentional (grouping multiple cases) but should be clearly commented. The default clause acts like else, handling values that don't match any case.

Looping statements

Loops execute code repeatedly, either a specific number of times or until a condition is met.

For loop

// Basic for loop structure
// for ([initialization]; [condition]; [increment]) { statements }

// Counting from 0 to 4
for (let i = 0; i < 5; i++) {
  console.log(`Iteration ${i}`);
}
// Output: Iteration 0, Iteration 1, ..., Iteration 4

// Counting backwards
for (let i = 10; i > 0; i--) {
  console.log(i);
}
// Output: 10, 9, 8, ..., 1

// Iterating through an array
const colors = ["red", "green", "blue", "yellow"];

for (let i = 0; i < colors.length; i++) {
  console.log(`Color ${i + 1}: ${colors[i]}`);
}

// Skipping iterations with continue
for (let i = 0; i < 10; i++) {
  if (i % 2 === 0) continue;  // Skip even numbers
  console.log(i);  // Only prints odd numbers
}

// Breaking out of loop early
for (let i = 0; i < 100; i++) {
  if (i === 5) break;  // Exit loop when i reaches 5
  console.log(i);
}
// Output: 0, 1, 2, 3, 4

// Nested loops (use cautiously - O(n²) complexity)
for (let i = 1; i <= 3; i++) {
  for (let j = 1; j <= 3; j++) {
    console.log(`i=${i}, j=${j}`);
  }
}

The for loop is ideal when you know how many iterations you need. It has three parts: initialization (runs once before the loop), condition (checked before each iteration), and increment (runs after each iteration). The loop variable (typically i) is commonly used to access array elements by index. The break statement exits the loop immediately, while continue skips the rest of the current iteration and moves to the next one. Nested loops multiply iteration counts—a loop inside a loop with 10 iterations each runs 100 times total.

For...of and for...in loops

// for...of - Iterates over VALUES (arrays, strings, iterables)
const fruits = ["apple", "banana", "cherry"];

for (const fruit of fruits) {
  console.log(fruit);
}
// Output: apple, banana, cherry

// for...of with strings
const message = "Hello";
for (const char of message) {
  console.log(char);
}
// Output: H, e, l, l, o

// for...in - Iterates over KEYS/INDICES (object properties, array indices)
const person = {
  name: "John",
  age: 30,
  city: "New York"
};

for (const key in person) {
  console.log(`${key}: ${person[key]}`);
}
// Output: name: John, age: 30, city: New York

// for...in with arrays (returns indices, not recommended)
const numbers = [10, 20, 30];

for (const index in numbers) {
  console.log(`Index ${index}: ${numbers[index]}`);
}
// Output: Index 0: 10, Index 1: 20, Index 2: 30

// Key difference demonstrated
const arr = [3, 5, 7];
arr.customProperty = "hello";

for (const i in arr) {
  console.log(i);  // Logs: 0, 1, 2, customProperty
}

for (const value of arr) {
  console.log(value);  // Logs: 3, 5, 7 (only array values)
}

While and do...while loops

// While loop - Check condition first, then execute
let count = 0;

while (count < 5) {
  console.log(`Count: ${count}`);
  count++;
}
// Output: Count: 0, Count: 1, ..., Count: 4

// While loop with condition that may never be true
let found = false;
let attempts = 0;

while (!found && attempts < 10) {
  attempts++;
  console.log(`Attempt ${attempts}`);
  // Simulated condition
  if (Math.random() > 0.7) {
    found = true;
    console.log("Success!");
  }
}

// Do...while - Execute first, then check condition (runs at least once)
let userInput;

do {
  userInput = prompt("Enter 'quit' to exit:");
  console.log(`You entered: ${userInput}`);
} while (userInput !== "quit");

// Comparison: while vs do...while
let x = 10;

while (x < 5) {
  console.log("This never runs");
}

do {
  console.log("This runs once even though condition is false");
} while (x < 5);

While loops repeat code as long as a condition is true, making them ideal when the number of iterations is unknown. The while loop checks the condition before executing, so the body may never run. The do...while loop checks the condition after executing, guaranteeing at least one execution. Use while for scenarios like processing input until a condition is met, searching for values, or waiting for external events. Always ensure the loop condition will eventually become false to avoid infinite loops.

Avoiding Infinite Loops

// Infinite loop - AVOID! This will freeze your browser
// while (true) {
//   console.log("This never stops!");
// }

// Common infinite loop mistakes
// let i = 0;
// while (i < 10) {
//   console.log(i);
//   // Forgot to increment i - infinite loop!
// }

// Safe patterns
let counter = 0;
const MAX_ITERATIONS = 1000;

while (counter < MAX_ITERATIONS) {
  // Do work
  counter++;  // Always increment/change condition variable
  
  // Safety exit
  if (someErrorCondition) {
    console.error("Breaking due to error");
    break;
  }
}

// Set timeout to prevent truly infinite loops in development
let iterations = 0;
while (someCondition) {
  iterations++;
  if (iterations > 10000) {
    console.error("Loop exceeded safety limit");
    break;
  }
  // Loop body
}

Best practices

1. Use modern variable declarations

// Bad - using var
var oldWay = "avoid this";

// Good - use const by default
const API_URL = "https://api.example.com";
const MAX_RETRIES = 3;

// Good - use let when reassignment is needed
let counter = 0;
counter++;

2. Write clear function names

// Bad - unclear names
function doStuff(x) { }
function process(data) { }

// Good - descriptive names
function calculateTotalPrice(items) { }
function validateUserEmail(email) { }
function fetchUserDataFromAPI(userId) { }

3. Keep functions small and focused

// Bad - function does too much
function processUser(user) {
  // Validate user
  // Calculate age
  // Format data
  // Send email
  // Update database
}

// Good - single responsibility
function validateUser(user) { }
function calculateAge(birthDate) { }
function formatUserData(user) { }
function sendWelcomeEmail(email) { }
function saveUserToDatabase(user) { }

4. Use strict equality

// Bad - loose equality
if (value == "5") { }
if (result != null) { }

// Good - strict equality
if (value === "5") { }
if (result !== null) { }

5. Comment complex logic, not obvious code

// Bad - obvious comments
let x = 5;  // Set x to 5

// Good - explain WHY, not WHAT
// Using 5-second debounce to prevent excessive API calls
const DEBOUNCE_DELAY = 5000;

// Complex regex for email validation per RFC 5322 spec
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;

Good JavaScript code is readable, maintainable, and follows established conventions. Use const by default and let only when reassignment is necessary—never use var. Write descriptive function and variable names that explain purpose. Keep functions small and focused on a single task. Always use strict equality (===) to avoid type coercion bugs. Comment complex logic, algorithms, or business rules, but don't comment obvious code—good code should be self-documenting through clear naming.

Last updated

Was this helpful?