JavaScript · lesson 2 of 24
Beginner
11- 1 Introduction to JavaScript
- 2 Setting Up JavaScript Development Environment
- 3 Variables in JavaScript: var, let, and const
- 4 JavaScript Data Types
- 5 JavaScript Operators
- 6 Control Flow in JavaScript
- 7 Functions in JavaScript
- 8 Working with Strings in JavaScript
- 9 Arrays in JavaScript
- 10 Objects in JavaScript
- 18 DOM Manipulation in JavaScript
Intermediate
10- 11 Error Handling in JavaScript
- 12 Object-Oriented Programming in JavaScript
- 13 Prototypes and Prototype Chain in JavaScript
- 14 Closures in JavaScript
- 15 JavaScript Event Loop Explained
- 16 Asynchronous JavaScript: Callbacks, Promises, and Async/Await
- 17 JavaScript Modules: ESM and CommonJS
- 19 Browser Web APIs in JavaScript
- 20 Testing JavaScript with Jest and Vitest
- 24 JavaScript Interview Preparation: Top 35 Questions
Advanced
3Setting Up JavaScript Development Environment
Install Node.js and npm, configure VS Code with the right extensions, and run your first JavaScript program from the terminal.
By SkillByExample · Updated
What You Need
Before writing any code, it helps to understand what each tool does. Node.js is the runtime that lets JavaScript execute outside the browser — on your machine, on servers, anywhere. npm is the package manager bundled with Node.js that gives you access to millions of open-source libraries. VS Code is the editor: it understands JavaScript deeply, offering autocomplete, inline errors, and a built-in terminal.
To follow along with this tutorial series you need:
- Node.js (LTS) — the JavaScript runtime for running code outside the browser
- npm — the package manager, bundled with Node.js automatically
- VS Code — the most widely used editor for JavaScript development
- A terminal (PowerShell on Windows, Terminal on macOS/Linux)
Installing Node.js
Node.js has two release lines: Current (latest features) and LTS (Long-Term Support). For learning and for any serious project, always choose LTS — it receives security patches for 30 months and is what the broader ecosystem targets.
Go to nodejs.org and download the LTS installer for your operating system. The installer also installs npm.
After installation, verify both are available:
node --version
npm --version
$ node --version
v24.18.1
$ npm --version
11.1.0
Node 24 is an LTS line, and npm 11 ships with Node 24. Your numbers will differ with the release you installed. What matters is that both commands print a version instead of command not found. If one fails, close and reopen the terminal so it picks up the updated PATH.
Using a Version Manager (Recommended)
As you work on more projects you’ll eventually encounter situations where different projects require different versions of Node. A version manager solves this cleanly — it lets you install multiple Node versions side by side and switch between them with one command.
- Windows: nvm-windows
- macOS/Linux: nvm or fnm
# With nvm installed:
nvm install --lts # install latest LTS
nvm use --lts # activate it
nvm install 22 # install a specific version
nvm use 22 # switch to it
Installing VS Code
Download from code.visualstudio.com. It’s free and available for Windows, macOS, and Linux.
Essential Extensions
VS Code’s power comes from its extension ecosystem. These five extensions cover the essentials for JavaScript development — linting, formatting, path completion, and better error visibility. Install them from the Extensions panel (Ctrl+Shift+X / Cmd+Shift+X):
| Extension | Purpose |
|---|---|
| ESLint | Catches code quality issues and style violations |
| Prettier - Code formatter | Opinionated auto-formatter — formats on save |
| Path IntelliSense | Autocompletes file paths in import statements |
| JavaScript (ES6) code snippets | Useful shorthands for common patterns |
| Error Lens | Inline error and warning display |
Recommended VS Code Settings
These settings make the editor work the way most JavaScript teams expect. The most important one is formatOnSave — it means you never have to think about formatting; save the file and Prettier fixes it automatically.
Open settings (Ctrl+,) and add these to your settings.json:
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.tabSize": 2,
"editor.detectIndentation": false,
"javascript.updateImportsOnFileMove.enabled": "always"
}
The Browser Developer Tools Console
You don’t always need Node.js. For quick experiments and debugging, your browser’s built-in console is always available — no setup, no files. It’s the fastest way to test a snippet or explore how a built-in method works.
- Open Chrome, Edge, or Firefox
- Press
F12(or right-click → Inspect) - Click the Console tab
- Type JavaScript directly and press Enter
// Try this in the browser console
const nums = [1, 2, 3, 4, 5];
const doubled = nums.map(n => n * 2);
console.log(doubled);
The output below is not from a browser: a browser console can’t be captured from a terminal. It is the same four lines saved as console.js and run with Node:
$ node console.js
[ 2, 4, 6, 8, 10 ]
The first line is only a comment, so the code needs no changes to run in Node. Each element is doubled, and the result is a new array. A browser console prints the same values but formats the array its own way, usually as an expandable entry. The browser console is perfect for exploring DOM APIs, testing snippets, and debugging live pages.
Your First Node.js Program
Running JavaScript through Node.js is the foundation for everything in this series. It lets you execute any .js file from your terminal, access the filesystem, and use npm packages. Create a new folder and open it in VS Code:
mkdir js-practice && cd js-practice
code .
Create a file called hello.js:
// hello.js
// A simple function that returns a greeting string
function greet(name) {
return `Hello, ${name}! Welcome to JavaScript.`;
}
const names = ['Alice', 'Bob', 'Charlie'];
// forEach iterates the array and runs the callback for each element
names.forEach(name => {
console.log(greet(name));
});
Run it from the terminal inside VS Code (`Ctrl+“ to open it):
$ node hello.js
Hello, Alice! Welcome to JavaScript.
Hello, Bob! Welcome to JavaScript.
Hello, Charlie! Welcome to JavaScript.
forEach calls the arrow function once per name, in array order, and each call prints one line. The comment lines in the file produce no output.
Initializing a Project with npm
Most real projects depend on external packages — UI libraries, utility functions, testing frameworks. The package.json file is how Node.js tracks those dependencies and lets anyone clone your project and install everything they need with one command.
npm init -y
This creates a package.json with default values; the -y flag accepts every prompt. npm 11 also writes keywords, author, license and "type": "commonjs". Below is the file after replacing its scripts block by hand with start and dev scripts (npm init only adds a placeholder test script):
{
"name": "js-practice",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js",
"dev": "node --watch index.js"
}
}
The scripts block lets you define shortcuts that any contributor can run without knowing the underlying commands:
npm run start # runs "node index.js"
npm run dev # runs with --watch, auto-restarts on file change
node --watch was added in Node 18 and replaces the popular nodemon package for simple cases.
Running a Script with a Dependency
Installing a package and using it is the core npm workflow. Once you run npm install, the package is downloaded into node_modules/ and recorded in package.json — anyone who clones the repo can run npm install to get the exact same versions.
npm install chalk
Now use it in a script:
// colorful.js
// chalk adds ANSI color codes to terminal output
import chalk from 'chalk';
console.log(chalk.green('Success:'), 'Server started');
console.log(chalk.red('Error:'), 'Connection refused');
console.log(chalk.yellow('Warning:'), 'Disk usage above 80%');
For ES module imports (import syntax) you need to add "type": "module" to package.json:
{
"type": "module"
}
node colorful.js
You’ll see colored output in the terminal — chalk is a tiny but very practical package.
Project Structure Conventions
Keeping a predictable folder structure matters once a project grows beyond a handful of files. The most important rule: never commit node_modules/ — it can contain thousands of files and is always reproducible from package.json. Here is js-practice after npm install chalk, with the application code moved into src/index.js, listed with the tree utility (brew install tree / apt install tree) from the parent folder:
$ tree -a -L 2 --noreport js-practice
js-practice
├── .gitignore
├── node_modules
│ ├── .package-lock.json
│ └── chalk
├── package-lock.json
├── package.json
└── src
└── index.js
node_modules/ holds the installed packages. Here that is only chalk plus npm’s own bookkeeping file, but a real project can have thousands of entries, so never commit it. package-lock.json records the exact versions installed; commit it so every clone gets the same ones. Your code lives in src/.
Your .gitignore should always include these three lines:
$ cat js-practice/.gitignore
node_modules/
.env
dist/
.env holds local secrets such as API keys, and dist/ holds build output that can be regenerated, so neither belongs in Git.
Practice
- Change
hello.jsso each greeting is numbered, starting at 1, and add'Dana'to the array.forEachpasses the element’s index as the callback’s second argument.
Solution
// hello.js
function greet(name, position) {
return `${position}. Hello, ${name}! Welcome to JavaScript.`;
}
const names = ['Alice', 'Bob', 'Charlie', 'Dana'];
// forEach passes the index as the callback's second argument
names.forEach((name, index) => {
console.log(greet(name, index + 1));
});
$ node hello.js
1. Hello, Alice! Welcome to JavaScript.
2. Hello, Bob! Welcome to JavaScript.
3. Hello, Charlie! Welcome to JavaScript.
4. Hello, Dana! Welcome to JavaScript.
Indexes start at 0, so index + 1 produces the human-friendly numbering. Adding a name to the
array is all it takes to get a fourth line, because forEach visits every element.
- Move the browser-console snippet into a file called
doubled.js. Add a secondmapthat squares each number, and printnumslast. Before running it, predict whethernumshas changed.
Solution
// doubled.js
const nums = [1, 2, 3, 4, 5];
const doubled = nums.map(n => n * 2);
const squared = nums.map(n => n * n);
console.log(doubled);
console.log(squared);
console.log(nums);
$ node doubled.js
[ 2, 4, 6, 8, 10 ]
[ 1, 4, 9, 16, 25 ]
[ 1, 2, 3, 4, 5 ]
map builds a new array and leaves the original alone, so nums prints unchanged. The same
code runs in the browser console and in Node; only the array formatting differs.
- Run
npm init -y, then edit thescriptsblock inpackage.jsonsonpm run startrunshello.jsand a new script,doubled, runsdoubled.js. Run both.
Solution
"scripts": {
"start": "node hello.js",
"doubled": "node doubled.js"
}
$ npm run start
> js-practice@1.0.0 start
> node hello.js
1. Hello, Alice! Welcome to JavaScript.
2. Hello, Bob! Welcome to JavaScript.
3. Hello, Charlie! Welcome to JavaScript.
4. Hello, Dana! Welcome to JavaScript.
$ npm run doubled
> js-practice@1.0.0 doubled
> node doubled.js
[ 2, 4, 6, 8, 10 ]
[ 1, 4, 9, 16, 25 ]
[ 1, 2, 3, 4, 5 ]
npm prints the package name, version, script name and the exact command before running it.
Any key you add under scripts becomes something you can run with npm run <key>.
- Install chalk and add a fourth line to
colorful.jsthat prints a blueInfo:label. Recent npm versions write"type": "commonjs"intopackage.jsonduringnpm init -y. If yours did, runcolorful.jsonce before you change it, then change the value to"module"and run it again.
Solution
// colorful.js
import chalk from 'chalk';
console.log(chalk.green('Success:'), 'Server started');
console.log(chalk.red('Error:'), 'Connection refused');
console.log(chalk.yellow('Warning:'), 'Disk usage above 80%');
console.log(chalk.blue('Info:'), 'Listening on port 3000');
With "type": "commonjs" (Node v24.18.1, npm 11.1.0):
$ node colorful.js
(node:7532) Warning: Failed to load the ES module: S:\js-practice\colorful.js. Make sure to set "type": "module" in the nearest package.json file or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)
S:\js-practice\colorful.js:2
import chalk from 'chalk';
^^^^^^
SyntaxError: Cannot use import statement outside a module
at wrapSafe (node:internal/modules/cjs/loader:1804:18)
at Module._compile (node:internal/modules/cjs/loader:1845:20)
at Object..js (node:internal/modules/cjs/loader:2002:10)
at Module.load (node:internal/modules/cjs/loader:1594:32)
at Module._load (node:internal/modules/cjs/loader:1396:12)
at wrapModuleLoad (node:internal/modules/cjs/loader:255:19)
at Module.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:154:5)
at node:internal/main/run_main_module:33:47
Node.js v24.18.1
After changing it to "type": "module":
$ node colorful.js
Success: Server started
Error: Connection refused
Warning: Disk usage above 80%
Info: Listening on port 3000
$ npm ls
js-practice@1.0.0 S:\js-practice
└── chalk@6.0.1
"commonjs" tells Node to treat .js files as CommonJS, where import is a syntax error. In a
terminal the labels are coloured; this captured output is plain text, so the colour codes are
missing. npm ls confirms chalk is the only dependency.
What’s Next
With your environment ready, the next tutorial dives into variables — var, let, and const — and the scoping rules that trip up beginners and experienced developers alike.