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
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 JavaScript mixes behavior with structure, making code difficult to maintain and debug. It's acceptable for quick prototypes or learning, but production code should use external files. Inline scripts also can't be cached by browsers and pose security risks.
2. Internal JavaScript (script tags)
Internal JavaScript is useful for page-specific scripts that won't be reused. Placing script tags before the closing </body> tag ensures the DOM is fully loaded before JavaScript executes. This prevents errors from trying to access elements that don't exist yet.
3. External JavaScript files (recommended)
External JavaScript files are the professional standard for several reasons: code can be cached by browsers for better performance, the same file can be reused across multiple pages, separation of concerns keeps HTML clean, and team collaboration is easier. The defer attribute loads scripts asynchronously without blocking page rendering, executing them in order after the DOM is ready. The async attribute loads scripts asynchronously and executes them immediately, useful for independent scripts like analytics.
JavaScript syntax fundamentals
Statements and Comments
JavaScript code consists of statements that perform actions. Each statement typically ends with a semicolon (optional but recommended).
Case sensitivity and naming conventions
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
Use const by default for all variables. Only use let when you need to reassign the variable. Avoid var entirely in modern JavaScript—it has confusing scoping rules (function-scoped rather than block-scoped) and can be redeclared, leading to bugs. The const keyword prevents reassignment of the variable reference but doesn't make objects or arrays immutable; their contents can still be modified.
JavaScript Data Types
JavaScript has eight data types: seven primitive types and objects.

Primitive Data Types
Primitive types are immutable—their values cannot be changed after creation. When you "modify" a string or number, you're actually creating a new value. Strings can use single quotes, double quotes, or backticks (template literals). Template literals support multi-line strings and variable interpolation using ${expression} syntax. Numbers include special values like Infinity and NaN (Not a Number). Use null to explicitly represent "no value" and let undefined naturally occur for uninitialized variables.
Object data type
Type checking and conversion
The typeof operator returns "object" for null, which is a historical JavaScript bug that can't be fixed without breaking legacy code. To check for null specifically, use value === null. Arrays also return "object", so use Array.isArray() to properly detect arrays. JavaScript performs automatic type coercion, which can cause unexpected results: addition (+) favors strings while other math operators favor numbers. Understanding truthy and falsy values is crucial for conditionals—empty strings, 0, null, undefined, NaN, and false are falsy; everything else is truthy.
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
Function declarations define reusable code blocks with a name, parameters (inputs), and an optional return value (output). Parameters act as placeholders for values passed when calling the function. Default parameters (ES6+) provide fallback values if arguments aren't supplied. If a function doesn't explicitly return a value, it automatically returns undefined. The return statement immediately exits the function—any code after it won't execute.
Function Scope
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 expressions assign functions to variables, making functions first-class values that can be passed as arguments or returned from other functions. Arrow functions (=>) provide concise syntax, especially useful for short functions and callbacks. If the function body is a single expression, you can omit the braces and return keyword—the expression's value is automatically returned. Single parameters don't need parentheses, but multiple parameters or no parameters require them. Arrow functions also have different this binding behavior (covered in Advanced JavaScript).
Operators
JavaScript provides various operators for performing operations on values and variables.

Arithmetic operators
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
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
Always use strict equality (===) and strict inequality (!==) instead of loose equality (==) and loose inequality (!=). Loose equality performs type coercion, leading to confusing results like 0 == false being true. Strict equality checks both value and type without coercion, making code more predictable. The only exception is null == undefined, which is true by design—but even then, explicit checks are clearer.
Logical operators
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
The ternary operator provides concise syntax for simple conditional assignments. It's perfect for straightforward true/false scenarios but can become unreadable when nested. For complex conditions with multiple branches, traditional if/else statements are clearer and more maintainable. Use ternary operators for simple cases and readability; avoid deeply nested ternaries that require mental gymnastics to parse.
Conditional statements
Conditional statements control program flow based on boolean conditions.
If / Else If / Else
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 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
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
Use for...of to iterate over values in arrays, strings, and other iterables—it's cleaner and more intuitive for most use cases.
Use for...in to iterate over object properties. While for...in technically works with arrays, it iterates over indices (and any custom properties) rather than values, which is rarely what you want. For arrays, prefer for...of, array methods like forEach(), or traditional for loops.
The for...in loop is best reserved for objects where you need to access keys dynamically.
While and do...while loops
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 loops occur when the loop condition never becomes false, freezing browsers and crashing applications. Common causes include forgetting to update the loop variable, incorrect comparison operators, or logical errors in the condition. Always ensure your loop has a clear termination condition and that variables affecting the condition are properly updated. In development, consider adding safety counters that break after a maximum number of iterations to catch accidental infinite loops early.
Best practices
1. Use modern variable declarations
2. Write clear function names
3. Keep functions small and focused
4. Use strict equality
5. Comment complex logic, not obvious code
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?