Learn JS Series (#1) - What Is JavaScript, Why It Runs Everywhere, and How to Run It

in StemSocial29 days ago

Learn JS Series (#1) - What Is JavaScript, Why It Runs Everywhere, and How to Run It

js-banner.png

What will I learn

  • You will learn what JavaScript actually is, and why it has almost nothing to do with Java;
  • why one single language ended up running in browsers, on servers, on the desktop, and on tiny devices;
  • the difference between JavaScript the language and the runtimes that execute it (the single most important idea in this episode);
  • how to run JavaScript three different ways: the browser console, the Node REPL, and a real file;
  • a first taste of the features that make JavaScript genuinely distinctive, not just "the browser language".

Requirements

  • A working modern computer running macOS, Windows or Ubuntu;
  • An installed Node.js (20+) distribution, or just a modern browser console;
  • The ambition to learn JavaScript programming.

Difficulty

  • Beginner

Curriculum (of the Learn JS Series):

Learn JS Series (#1) - What Is JavaScript, Why It Runs Everywhere, and How to Run It

Welcome to the first episode of what is going to be a very long journey. My goal for this series is not a modest one: I want someone who has never written a single line of code to follow along and, by the end, understand JavaScript more deeply than most people who write it professionally for a living. That includes understanding the engine that runs it, the event loop that schedules it, and the corners of the language that trip up even senior engineers.

That is a big promise, so let's start at the very beginning, because the beginning of JavaScript is honestly a bit of a strange story. And knowing the story matters -- quite some of JavaScript's weirdness only makes sense once you know where it came from and how much pressure it was born under.

JavaScript is not Java (and the name is a marketing accident)

JavaScript was created in 1995 by Brendan Eich, at Netscape, in about ten days. Let that sink in for a moment: the language now running on billions of devices was prototyped in roughly a week and a half. It was originally called Mocha, then LiveScript, and was finally renamed JavaScript purely because Java was the hot language of the moment and Netscape's marketing wanted to ride that wave. The two languages are almost entirely unrelated. A famous line captures it well -- Java and JavaScript are alike in the way that "car" and "carpet" are alike.

The actual standard behind the language is called ECMAScript (because it is standardized by a body called Ecma International). When you hear "ES6" or "ES2015" or "ES2020", that is a version of the ECMAScript specification. So the mental model is: JavaScript is the language you write; ECMAScript is the spec it follows. New features land in the spec every year now, which is why the language you will learn in this series is a genuinely modern, capable one and not the clumsy toy people remember from 2005. We will even read small bits of that spec later on, and you will see it is far less scary than it sounds.

Why does the ten-days-in-a-week origin matter to you as a learner? Because it explains the language's split personality. There are parts of JavaScript that are beautifully designed (first-class functions, closures, the flexible object model) and parts that are frankly a mess (the == operator, a couple of the type coercions, null versus undefined). Both live in the same language, side by side. A big part of learning JavaScript well -- as opposed to just getting by -- is knowing which parts to lean on and which parts to route around. I will point those out as we go.

One language, running absolutely everywhere

For its first decade, JavaScript only lived inside web browsers. Then in 2009 a project called Node.js took Google's JavaScript engine (V8, the very one inside Chrome) and wrapped it so it could run outside the browser, directly on your operating system. Suddenly you could write servers, command-line tools, and build scripts in the same language you used for web pages. That was a genuinely HUGE moment, because it turned a browser-only scripting toy into a general-purpose language overnight.

Today JavaScript runs in an enormous range of places:

  • In every web browser (Chrome, Firefox, Safari, Edge).
  • On servers, via Node.js, Deno, and Bun.
  • On the desktop, via Electron -- VS Code, Slack and Discord are all JavaScript apps wearing a native coat.
  • On phones, via React Native and similar frameworks.
  • On microcontrollers and embedded devices, via projects like Espruino.

That reach is exactly why learning it well pays off so much: one language, and you can touch nearly every kind of computing surface there is. But that reach also forces us to be very precise about one thing, and it is the thing beginners trip over most.

The language versus the runtime

This is the single most important idea in this first episode, so I want to be completely explicit about it, and I will keep coming back to it all series long.

JavaScript the language is a small, portable core: variables, functions, objects, numbers, strings, control flow, and a handful of built-in types. That core is identical whether you run it in Chrome or on a server. const x = 5, a for loop, a function definition -- these behave the same everywhere, because they are pure language.

A runtime is the environment that hosts the language and gives it extra powers. The browser runtime hands JavaScript the ability to touch the web page (the DOM) and react to clicks. The Node.js runtime hands JavaScript the ability to read files and open network sockets. Neither of those abilities is part of the language itself -- they are provided by the host, bolted on around the same shared core.

So document.querySelector(...) only exists in a browser, and require('fs') (reading the file system) only exists in Node. But const total = 2 + 2 works everywhere, because it is pure language. Keep this distinction firmly in your head. A whole category of beginner confusion -- "why does this code work in Chrome but crash in Node?" -- simply melts away once you internalize it. The answer is almost always: you reached for a runtime power that the other host does not provide.

Here is the same idea shown as code. Both snippets are perfectly valid JavaScript, but each only runs in one home:

// Pure language -- runs in a browser, in Node, in Deno, anywhere:
const price = 10;
const withTax = price * 1.21;
console.log(withTax); // 12.1

// Runtime-specific -- this line ONLY works inside a browser page,
// because `document` is a power the browser host provides, not the language:
// document.querySelector("h1").textContent = "Hi";

For most of this early phase we will write pure-language code, so it runs anywhere and you never get blocked by "that only works in a browser". Once the foundations are solid, we will deliberately step into the browser platform and into Node, and by then the split will feel obvious in stead of mysterious. Now, let me show you the three ways to actually run this stuff.

Way 1: the browser console

Open any web browser, press F12 (or right-click the page and choose Inspect), and click the Console tab. You now have a live JavaScript prompt sitting right there. Type this and press Enter:

console.log("Hello from the browser");

console.log prints whatever you give it to the console. It is the most-used function in all of JavaScript, and you will type it thousands of times over your career, so get comfortable with it now. Congratulations -- you just ran your first program, and you did not have to install a single thing to do it.

The browser console is also the fastest place to poke at the DOM later, because you are literally sitting inside a live page. But for learning the language core, we want something a little more permanent, which brings us to Node.

Way 2: installing Node and using the REPL

For the rest of this series I will assume you have Node.js installed, because it lets us run JavaScript without opening a browser at all. Download it from nodejs.org (get version 20 or newer -- older versions are missing features we will use). To check it worked, open a terminal and run:

node --version

If that prints something like v20.x or newer, you are ready. Now just type node on its own and press Enter. You are dropped into the REPL (short for Read-Eval-Print-Loop), an interactive prompt exactly like the browser console but living in your terminal:

console.log(2 + 2);        // 4
console.log("hi".length);  // 2
console.log(typeof 42);    // "number"

The REPL is perfect for quick experiments: type an expression, get an answer, immediately try the next one. It is where I test tiny ideas before committing them to a file. When you are done, press Ctrl-C twice (or type .exit) to leave it.

Way 3: running a real file

Experiments are lovely, but real programs live in files you can save, edit, and re-run. Create a file called hello.js and put this inside it:

console.log("Hello from a file");

const name = "scipio";
console.log("This series is written by " + name);

Then run it from your terminal, from the same folder the file lives in:

node hello.js

You should see both lines printed. That right there is the workflow you will use constantly for the rest of the series, and honestly for the rest of your programming life: edit a .js file, run it with node, read the output, adjust, repeat. It is a tight little loop, and the tighter you can make it, the faster you learn.

A first taste of what makes JavaScript special

I do not want to end a first episode with just "here is how to print text". So let me show you four small things that hint at what is coming, so you get a real feel for the language's personality before we slow down and do each one properly in later episodes.

First, JavaScript is dynamically typed. You do not declare that a variable holds a number or a string; a variable simply holds whatever value you put in it, and that can change while the program runs:

let thing = 42;             // right now it holds a number
console.log(typeof thing);  // "number"

thing = "now a string";     // totally allowed, no error
console.log(typeof thing);  // "string"

typeof reports the type of a value at runtime. That flexibility is powerful and, occasionally, genuinely dangerous -- a whole chunk of this series is about wielding it wisely rather than getting cut by it. If you have come from a language like C, Java, or Rust, where a variable's type is fixed forever the moment you declare it, this will feel loose to the point of reckless. It is a real trade-off, and later on I will show you TypeScript, which bolts static types back on top.

Second, and this is the beating heart of the language, functions are values. In JavaScript a function is just another thing you can store in a variable, pass to another function, and return as a result:

const greet = function (who) {
  return "Hello, " + who + "!";
};

console.log(greet("world")); // "Hello, world!"

We stored a function in a variable called greet and then called it through that variable. Coming from Python this looks familiar, but JavaScript leans on this idea far harder than most languages, and it is the foundation for closures, callbacks, and the entire async model we will spend serious time on later. When people say JavaScript is a "functional-ish" language, this is what they mean: functions are ordinary values, first-class citizens, not some special second-class construct.

Because functions are values, you can even pass one function into another. Here a function receives another function and calls it twice -- do not sweat the mechanics yet, just notice that fn is a value being handed around like any number or string:

function twice(fn, x) {
  return fn(fn(x));
}

const addOne = function (n) {
  return n + 1;
};

console.log(twice(addOne, 5)); // 7  -- addOne applied twice to 5

Third, JavaScript has a compact, very readable way to build text called template literals, written with backticks instead of quotes:

const user = "scipio";
const episode = 1;
console.log(`Welcome ${user}, this is episode ${episode}.`);

Inside backticks, anything you put in ${...} is evaluated and dropped straight into the string. That is enormously nicer than gluing pieces together with + (which we did up in hello.js, and which gets ugly fast), and we will use template literals absolutely everywhere from here on.

Fourth, just so you have seen a loop, here is JavaScript counting. Do not worry about the exact syntax yet -- we cover loops properly in a later episode -- just read it and see that it does what it looks like it does:

for (let i = 1; i <= 3; i++) {
  console.log(`counting: ${i}`);
}

That prints counting: 1, then counting: 2, then counting: 3. In just these few snippets you have already seen variables, dynamic types, functions as values, higher-order functions, template strings, and a loop -- all in a language that was designed in ten days and now quietly runs the world. Not bad for episode one ;-)

Putting a few pieces together

Individual features are one thing, but programming is about combining them. Let me tie the taste-test together into one slightly bigger program you can drop into a file and run with node. It builds a greeting for each name in a list, using a function, a loop, and a template literal all at once:

const names = ["ada", "linus", "grace"];

function welcome(who) {
  return `Welcome aboard, ${who}!`;
}

for (const person of names) {
  console.log(welcome(person));
}

Run that and you get three lines of welcome, one per name. The for (const person of names) form is a clean way to walk through a list, welcome is our reusable function, and the backtick string stitches each name into a sentence. Nothing here is advanced, yet it is already a real little program with structure -- data, a function, and a loop working together. That combining is the whole game, and we will get very good at it.

How this compares to Python, Rust and Go

A lot of you are arriving here after the Learn Python Series (as, honestly, did I -- Python was my teaching language for years). So a look sideways at a few other languages sharpens the picture of where JavaScript sits.

Take our earlier example -- a variable that holds a number and then holds a string. Here is the same idea in three languages:

# Python -- also dynamically typed, so this is allowed, just like JS:
thing = 42
thing = "now a string"
print(type(thing))   # <class 'str'>

Python behaves much like JavaScript here: variables are dynamically typed, so reassigning to a different type is fine. The two languages feel like cousins in this respect. But Rust and Go slam that door shut, because they are statically typed -- the type is decided at compile time and fixed:

// Rust -- this does NOT compile. `thing` is an integer, forever.
// let mut thing = 42;
// thing = "now a string"; // error: mismatched types
// Go -- also rejected at compile time for the same reason:
// thing := 42
// thing = "now a string" // error: cannot use string as int value

In Rust and Go the compiler catches that mistake before the program ever runs, which prevents a whole class of bugs -- at the cost of the flexibility JavaScript and Python give you. So there is the spectrum, and it is worth carrying in your head: Python and JavaScript sit on the flexible, dynamic end (fast to write, mistakes surface at runtime), while Rust and Go sit on the strict, static end (more up-front ceremony, mistakes caught early). Neither end is "correct" -- they are different trade-offs for different jobs. And later in this series, TypeScript will let you slide JavaScript part way toward the strict end whenever a project wants it, which is one of the loveliest things about the JS ecosystem.

The other big difference is reach, which we already met. Python is superb on the server and in data work, but it does not run in your browser. JavaScript is the only language that runs natively in every browser on Earth, and it also runs on the server via Node. That combination -- one language for both the page a user sees and the server behind it -- is a genuinely rare superpower, and it is a big reason JavaScript is worth learning deeply rather than just tolerating.

Try it yourself

Three small exercises. Have a real go at each before the next episode -- typing it yourself is where the learning actually sticks, and the full worked solutions will open the next episode.

  1. Open the Node REPL and compute, in a single expression, how many seconds there are in one week. (Hint: multiply the right numbers together and console.log the result. You should land on 604800.)
  2. Create a file called about.js that stores your first name in one const, your favourite number in another const, and then prints a single sentence using a template literal that includes both values. Run it with node about.js.
  3. In the REPL, put a number into a let variable and print its typeof. Then reassign the same variable to a string and print its typeof again. Watch the reported type change at runtime, and write down, in your own words, why that is different from what would happen in a statically typed language like Rust or Go.

So what did we actually cover?

  • JavaScript was created in 1995 by Brendan Eich in about ten days, and the name is a marketing nod to Java -- a completely different, unrelated language.
  • The formal standard is called ECMAScript; versions like ES2015 and ES2020 are yearly editions of that spec, and modern JavaScript is a capable, still-growing language.
  • The same language runs in browsers, on servers (Node, Deno, Bun), on the desktop (Electron), and on small devices -- that reach is why learning it well pays off.
  • The most important idea of the episode: the language (variables, functions, objects) is a portable core, while a runtime adds host powers like the DOM (browser) or the file system (Node). They are not the same thing, and separating them clears up most early confusion.
  • You can run JavaScript three ways: the browser console, the Node REPL, and a .js file executed with node.
  • A first taste of the language's character: dynamic typing, functions as values, higher-order functions, and template literals -- plus how JS sits on the flexible/dynamic end of the spectrum next to Python, opposite the strict/static Rust and Go.

We have the map and we know how to run code. From here the series slows down and builds real foundations, brick by brick. The very next thing we need to nail down is how JavaScript actually stores your data: the different ways to declare a variable, how they differ, and which one you should reach for by default (there is a clear winner, and the reason why is more interesting than you would expect). One thing at a time ;-)

Thanks for reading, and see you in the next one.

@scipio

Sort:  

Thank you!

Were you hoping for a comprehensive "learn JavaScript from the start to mastery"?
Well here you go! (I am building a learn to program platform, and I am pre-publishing lessons on my Hive profile, I've already written - but not published yet anywhere - all my Learn JS episodes).
It'll go deep! Have fun!

@scipio

Yes, precisely 👏 I am very interested to learn. Thanks for your efforts!!

I just published JS ep.2 !! Take a look!
And keep in mind I tend to publish one new JS episode per day, more or less at the same time of day as well.