JavaScript Get Started
JavaScript is the programming language that makes web pages interactive. It runs inside every modern browser and, thanks to Node.js, on servers and command lines too. In this lesson you’ll learn what JavaScript actually is, how it gets executed, how to add it to a page or run it directly, and you’ll write your first real programs.
Overview: What JavaScript Is and How It Works
JavaScript (often shortened to JS) was created in 1995 and is standardized today under the name ECMAScript. Every browser ships with a JavaScript engine that reads your code and runs it: Chrome and Node.js use V8, Firefox uses SpiderMonkey, and Safari uses JavaScriptCore. Because Node.js embeds the V8 engine outside the browser, the exact same language can build web pages, servers, command-line tools, and scripts.
When the engine receives your source code, it doesn’t just read it character by character and run it blindly. It performs several stages internally:
- Parsing — the raw text is broken into tokens (keywords, identifiers, punctuation) and organized into a tree structure called an Abstract Syntax Tree (AST) that represents the program’s structure.
- Compilation — modern engines use JIT (Just-In-Time) compilation, translating the AST into bytecode and, for hot code paths, further into optimized machine code, blending the speed of compiled languages with the flexibility of an interpreted one.
- Execution — the engine creates an execution context (a global one to start), sets up memory for variables and functions, and then runs your statements one at a time using a single call stack.
JavaScript is single-threaded: only one thing executes at a time on the call stack. To avoid freezing the page while waiting on slow operations (timers, network requests, file reads in Node), the engine hands those off to the browser or Node runtime, which queues their callbacks to run later via the event loop once the call stack is empty. You’ll explore the event loop in depth in later lessons — for now, just know that your top-level code always runs synchronously, top to bottom, first.
JavaScript is also dynamically typed: a variable isn’t locked to one type, and it’s loosely typed, meaning many operators will automatically convert (coerce) values between types. This flexibility is powerful but is also the source of some classic beginner bugs, which the Common Mistakes section below covers.
Syntax
Before writing programs, you need to know how to get JavaScript running. There are three common ways to add it to an HTML page, and a few universal rules for writing statements.
Adding JavaScript to a page
- Inline: code written directly inside a
<script>tag in the HTML file. - External file: a
<script src="app.js"></script>tag that loads a separate.jsfile — the standard approach for real projects, since it keeps HTML and logic separate and lets the browser cache the file. - Script placement: scripts are commonly placed at the end of
<body>, or in<head>with thedeferattribute, so the page’s HTML finishes loading before your script tries to interact with it.
You can also run JavaScript without any HTML at all: open your browser’s DevTools console (F12), or install Node.js and run a file with node app.js from a terminal. Node is how the examples in this lesson are meant to be tried out.
Basic statement rules
| Rule | Explanation |
|---|---|
| Case-sensitive | myVar and myvar are different identifiers. |
| Semicolons | Statements typically end with ;. JavaScript has Automatic Semicolon Insertion (ASI), which can insert one for you in some cases — but relying on it causes bugs (see Common Mistakes), so write them explicitly. |
| Comments | // single line and /* multi. |
| Declarations | let (reassignable), const (not reassignable), and the legacy var (avoid in modern code). |
| Blocks | Curly braces { } group statements for functions, loops, and conditionals. |
Here’s all of that in one small script:
// Declaring variables
let score = 10; // can be reassigned
const player = "Rae"; // cannot be reassigned
var legacy = "old-style"; // function-scoped, avoid in modern code
// A statement ends with a semicolon
score = score + 5;
// Comments
/* This is a
multi-line comment */
console.log(player, score);
Output:
Rae 15
let and const are block-scoped (they only exist inside the nearest { }), while var is function-scoped and gets hoisted in ways that confuse beginners — one of many reasons to prefer let/const.
Examples
Example 1: Your first program
// Your first JavaScript program
console.log("Hello, World!");
let message = "JavaScript is running!";
console.log(message);
Output:
Hello, World!
JavaScript is running!
console.log() is the standard way to print output while learning or debugging — in a browser it appears in DevTools; in Node it prints straight to your terminal. Each call runs in order, one after another, because the engine executes statements synchronously from top to bottom.
Example 2: Variables and template literals
const name = "Ada";
let age = 28;
const isLearning = true;
console.log(`${name} is ${age} years old.`);
console.log(`Currently learning JavaScript: ${isLearning}`);
age = age + 1;
console.log(`Next year, ${name} will be ${age}.`);
Output:
Ada is 28 years old.
Currently learning JavaScript: true
Next year, Ada will be 29.
This example mixes the three primitive types you’ll use constantly: a string (name), a number (age), and a boolean (isLearning). Template literals — strings wrapped in backticks with ${expression} placeholders — let you embed variables directly into text instead of concatenating with +. Notice age is declared with let because it’s reassigned later; name and isLearning use const because they never change.
Example 3: Functions and arrays working together
function greet(user) {
if (!user) {
return "Hello, stranger!";
}
return `Hello, ${user}!`;
}
console.log(greet("Grace"));
console.log(greet());
const numbers = [4, 8, 15, 16, 23, 42];
const total = numbers.reduce((sum, n) => sum + n, 0);
console.log(`Sum: ${total}`);
Output:
Hello, Grace!
Hello, stranger!
Sum: 108
The greet function shows a conditional return based on whether an argument was passed — calling greet() with nothing makes user undefined, which is falsy, so the stranger branch runs. numbers.reduce() is an array method that walks the array and accumulates a single value; here it sums every element into total. This is a realistic taste of how JavaScript combines functions, conditionals, and built-in array methods.
Under the Hood: How the Engine Executes Your Code
When a script starts, the engine creates a global execution context and a call stack — think of the stack as a pile of “what function am I currently inside of.” Every time a function is called, a new frame is pushed onto the stack; when that function returns, its frame is popped off. Trace it through this example:
function first() {
console.log("1. Start of first()");
second();
console.log("4. End of first()");
}
function second() {
console.log("2. Inside second()");
third();
}
function third() {
console.log("3. Inside third()");
}
console.log("0. Script starts");
first();
console.log("5. Script ends");
Output:
0. Script starts
1. Start of first()
2. Inside second()
3. Inside third()
4. End of first()
5. Script ends
Step by step: the global context runs console.log("0..."), then calls first(), pushing it onto the stack. Inside, it logs, then calls second() (pushed on top of first), which calls third() (pushed on top of second). third() finishes and is popped, control returns to second() which finishes and pops, control returns to first() which logs its final line and pops, and finally the global context logs the last line. This last-in-first-out order is exactly why deeply nested function calls that never return (infinite recursion) throw a “Maximum call stack size exceeded” error — the stack has a finite size.
Before execution even begins, the engine also does a hoisting pass: function declarations and var variables are registered in memory ahead of time (which is why you can call a function declared later in the file), while let and const are hoisted too but left in an uninitialized “temporal dead zone” until their declaration line actually runs — accessing them earlier throws a ReferenceError rather than silently returning undefined.
Common Mistakes
Mistake 1: Trusting Automatic Semicolon Insertion with return
JavaScript will insert a semicolon for you after return if the next token is on a new line, silently turning a multi-line object literal into a lost return value:
function getObject() {
return
{
name: "Oops"
};
}
console.log(getObject());
Output:
undefined
This parses without any syntax error, which makes it especially sneaky. ASI treats the line break after return as the end of the statement, so the function returns undefined and the object literal below becomes dead, unreachable code. The fix is to keep the opening brace on the same line as return:
function getObject() {
return {
name: "Fixed"
};
}
console.log(getObject());
Output:
{ name: 'Fixed' }
Mistake 2: Using == instead of ===
The loose equality operator == converts operands to a common type before comparing, which produces results many beginners don’t expect:
console.log(0 == "0");
console.log(0 === "0");
console.log("" == false);
console.log(null == undefined);
Output:
true
false
true
true
0 == "0" is true because the string is coerced to a number first, but 0 === "0" is false because === (strict equality) never converts types — it compares type and value together. Coercion rules like this are inconsistent enough ("" == false is true, but "" == 0 == false chained differently can surprise you) that the safest habit is to always reach for === and !== unless you have a specific, deliberate reason to allow coercion.
Best Practices
- Default to
const; switch toletonly for variables you know will be reassigned. Avoidvarentirely in new code. - Always use
===and!==instead of==and!=to sidestep unexpected type coercion. - Write semicolons explicitly rather than relying on ASI, especially around
return, array literals, and template literals. - Prefer template literals (
`${value}`) over string concatenation with+for readability. - Load scripts with
defer(or place them at the end of<body>) so your code can safely assume the page’s HTML already exists. - Keep JavaScript in external
.jsfiles rather than large inline blocks, so it can be cached, linted, and reused. - Use
console.log()liberally while learning — it’s the fastest way to check what a value actually is at any point in your code. - Give variables and functions descriptive names (
calculateTotal, notct) — the engine doesn’t care, but the next person reading your code does.
Practice Exercises
- Exercise 1: Declare three variables — your name (string), your age (number), and whether you’re currently learning to code (boolean). Use a template literal to log a single sentence that includes all three values.
- Exercise 2: Write a function
isEven(number)that returnstrueif a number is even andfalseotherwise (hint: use the remainder operator%). Call it with a few different numbers and log the results. - Exercise 3: Predict, on paper, what each of these logs before running them:
console.log(1 == "1"),console.log(1 === "1"), andconsole.log(undefined == null). Then try them in Node or your browser console and see if you were right.
Summary
- JavaScript is a dynamically typed, single-threaded language executed by an engine (V8, SpiderMonkey, JavaScriptCore) that parses your code into an AST, compiles it, and runs it via a call stack.
- You can run JavaScript inline in HTML, via an external
<script src="...">file, in a browser console, or with Node.js from a terminal. - Use
letandconstfor variables, template literals for string building, andconsole.log()to inspect output. - Code executes synchronously, top to bottom, using a call stack — understanding push/pop order explains both normal execution and stack overflow errors.
- Automatic Semicolon Insertion and loose equality (
==) are two of the most common early sources of bugs — write semicolons explicitly and prefer===. - You now have everything needed to start writing and running real JavaScript programs in the lessons ahead.
